LoRa_APRS_iGate/src/gps_utils.cpp

182 lines
7.5 KiB
C++
Raw Normal View History

2025-07-15 22:28:23 +02:00
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
*
* This file is part of LoRa APRS iGate.
*
* LoRa APRS iGate is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LoRa APRS iGate is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/
2025-11-30 14:15:01 +01:00
#include <APRSPacketLib.h>
#include <TinyGPS++.h>
2023-07-30 23:12:50 +02:00
#include <WiFi.h>
2023-06-06 18:19:56 +02:00
#include "configuration.h"
2024-11-05 22:20:44 +01:00
#include "board_pinout.h"
2023-06-08 06:58:10 +02:00
#include "gps_utils.h"
2024-06-07 23:29:55 +02:00
#include "display.h"
#include "utils.h"
2023-06-06 18:19:56 +02:00
2024-10-14 22:04:28 +02:00
#ifdef GPS_BAUDRATE
#define GPS_BAUD GPS_BAUDRATE
#else
#define GPS_BAUD 9600
#endif
extern Configuration Config;
extern HardwareSerial gpsSerial;
extern TinyGPSPlus gps;
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
2023-06-06 18:19:56 +02:00
2024-02-25 16:00:44 +01:00
2023-06-06 18:19:56 +02:00
namespace GPS_Utils {
2024-05-14 15:23:22 +02:00
String getiGateLoRaBeaconPacket() {
return iGateLoRaBeaconPacket;
}
2024-10-14 22:04:28 +02:00
void generateBeacons() {
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000);
Config.loramodule.txActive = false;
Config.aprs_is.messagesToRF = false;
Config.aprs_is.objectsToRF = false;
Config.beacon.sendViaRF = false;
Config.digi.mode = 0;
Config.backupDigiMode = false;
}
2025-11-30 14:15:01 +01:00
String beaconPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
2025-11-30 14:47:12 +01:00
String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(Config.beacon.latitude, Config.beacon.longitude, 0, 0, Config.beacon.symbol, false, 0, true, Config.beacon.ambiguityLevel);
2025-11-30 14:15:01 +01:00
iGateBeaconPacket = beaconPacket;
iGateBeaconPacket += ",qAC:!";
iGateBeaconPacket += Config.beacon.overlay;
2025-05-18 14:44:46 +02:00
iGateBeaconPacket += encodedGPS;
2025-11-30 14:15:01 +01:00
iGateLoRaBeaconPacket = beaconPacket;
iGateLoRaBeaconPacket += ":=";
iGateLoRaBeaconPacket += Config.beacon.overlay;
2024-06-08 20:39:15 +02:00
iGateLoRaBeaconPacket += encodedGPS;
2023-07-31 05:53:59 +02:00
}
2023-06-06 18:19:56 +02:00
2024-02-24 14:09:05 +01:00
double calculateDistanceTo(double latitude, double longitude) {
2024-03-07 17:46:38 +01:00
return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0;
}
2025-11-30 14:15:01 +01:00
String buildDistanceAndComment(float latitude, float longitude, const String& comment) {
distance = String(calculateDistanceTo(latitude, longitude),1);
String distanceAndComment = String(latitude,5);
distanceAndComment += "N / ";
distanceAndComment += String(longitude,5);
distanceAndComment += "E / ";
distanceAndComment += distance;
distanceAndComment += "km";
if (comment != "") {
distanceAndComment += " / ";
distanceAndComment += comment;
}
return distanceAndComment;
}
2024-05-15 23:47:29 +02:00
String decodeEncodedGPS(const String& packet) {
2025-03-18 22:50:08 +01:00
int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":=");
const uint8_t OFFSET = 3; // Offset for encoded data in the packet
2025-11-30 14:15:01 +01:00
String infoGPS;
2025-03-18 22:50:08 +01:00
if (indexOfExclamation > 10) {
2025-11-30 14:15:01 +01:00
infoGPS = packet.substring(indexOfExclamation + OFFSET);
2025-03-18 22:50:08 +01:00
} else if (indexOfEqual > 10) {
2025-11-30 14:15:01 +01:00
infoGPS = packet.substring(indexOfEqual + OFFSET);
2025-03-18 22:50:08 +01:00
}
2025-11-30 14:15:01 +01:00
float decodedLatitude = APRSPacketLib::decodeBase91EncodedLatitude(infoGPS.substring(0,4));
float decodedLongitude = APRSPacketLib::decodeBase91EncodedLongitude(infoGPS.substring(4,8));
return buildDistanceAndComment(decodedLatitude, decodedLongitude, infoGPS.substring(12));
2024-01-03 02:12:10 +01:00
}
2024-05-15 23:47:29 +02:00
String getReceivedGPS(const String& packet) {
2025-03-18 22:50:08 +01:00
int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":=");
int indexOfAt = packet.indexOf(":@");
2024-02-24 14:09:05 +01:00
String infoGPS;
2025-03-18 22:50:08 +01:00
if (indexOfExclamation > 10) {
infoGPS = packet.substring(indexOfExclamation + 2);
} else if (indexOfEqual > 10) {
infoGPS = packet.substring(indexOfEqual + 2);
} else if (indexOfAt > 10) {
infoGPS = packet.substring(indexOfAt + 9); // 9 = 2+7 (when 7 is timestamp characters)
2024-02-24 14:09:05 +01:00
}
2025-03-18 22:50:08 +01:00
String Latitude = infoGPS.substring(0,8); // First 8 characters are Latitude
float convertedLatitude = Latitude.substring(0,2).toFloat(); // First 2 digits (Degrees)
convertedLatitude += Latitude.substring(2,4).toFloat() / 60; // Next 2 digits (Minutes)
convertedLatitude += Latitude.substring(Latitude.indexOf(".") + 1, Latitude.indexOf(".") + 3).toFloat() / (60*100);
if (Latitude.endsWith("S")) convertedLatitude = -convertedLatitude; // Handle Southern Hemisphere
String Longitude = infoGPS.substring(9,18); // Next 9 characters are Longitude
float convertedLongitude = Longitude.substring(0,3).toFloat(); // First 3 digits (Degrees)
convertedLongitude += Longitude.substring(3,5).toFloat() / 60; // Next 2 digits (Minutes)
convertedLongitude += Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100);
if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere
2025-11-30 14:15:01 +01:00
return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));
}
2024-02-24 14:09:05 +01:00
2024-05-20 05:34:29 +02:00
String getDistanceAndComment(const String& packet) {
2025-03-18 22:50:08 +01:00
int indexOfAt = packet.indexOf(":@");
if (indexOfAt > 10) {
return getReceivedGPS(packet);
} else {
const uint8_t ENCODED_BYTE_OFFSET = 14; // Offset for encoded data in the packet
int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":=");
uint8_t encodedBytePosition = 0;
if (indexOfExclamation > 10) { // Determine the position where encoded data starts
encodedBytePosition = indexOfExclamation + ENCODED_BYTE_OFFSET;
} else if (indexOfEqual > 10) {
encodedBytePosition = indexOfEqual + ENCODED_BYTE_OFFSET;
}
if (encodedBytePosition != 0) {
char currentChar = packet[encodedBytePosition];
2025-12-18 13:28:56 +01:00
if (currentChar == 'G' || currentChar == 'Q' || currentChar == '[' || currentChar == 'H' || currentChar == 'X' || currentChar == '3') {
2025-03-18 22:50:08 +01:00
return decodeEncodedGPS(packet); // If valid encoded data position is found, decode it
} else {
return getReceivedGPS(packet);
}
2024-02-24 14:09:05 +01:00
} else {
2025-03-18 22:50:08 +01:00
return " _ / _ / _ ";
2024-02-24 14:09:05 +01:00
}
}
}
2024-10-14 22:04:28 +02:00
void setup() {
#ifdef HAS_GPS
2025-04-25 00:01:00 +02:00
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) {
2024-10-14 22:04:28 +02:00
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_TX, GPS_RX);
}
#endif
generateBeacons();
}
void getData() {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
}
2023-06-06 18:19:56 +02:00
}