diff --git a/common_settings.ini b/common_settings.ini index 18670bb..34ceac2 100644 --- a/common_settings.ini +++ b/common_settings.ini @@ -37,7 +37,7 @@ lib_deps = mathieucarbou/AsyncTCP @ 3.2.5 mathieucarbou/ESPAsyncWebServer @ 3.2.3 mikalhart/TinyGPSPlus @ 1.0.3 - richonguzman/APRSPacketLib @1.0.0 + richonguzman/APRSPacketLib @1.0.4 display_libs = adafruit/Adafruit GFX Library @ 1.11.9 adafruit/Adafruit SSD1306 @ 2.5.10 diff --git a/data/igate_conf.json b/data/igate_conf.json index 231658d..6148480 100644 --- a/data/igate_conf.json +++ b/data/igate_conf.json @@ -21,7 +21,7 @@ "statusActive": false, "statusPacket": "", "gpsActive": false, - "gpsAmbiguity": false + "ambiguityLevel": 0 }, "aprs_is": { "active": false, diff --git a/data_embed/index.html b/data_embed/index.html index e3231e0..0690b51 100644 --- a/data_embed/index.html +++ b/data_embed/index.html @@ -189,18 +189,10 @@ name="action.symbol" id="action.symbol" > - - - - + + + +
- - + +
@@ -616,6 +604,23 @@ +
+ + +
-
-
- - -
-

@@ -723,15 +713,9 @@ name="digi.mode" id="digi.mode" > - - - + + +
@@ -748,15 +732,9 @@ name="digi.ecoMode" id="digi.ecoMode" > - - - + + +
diff --git a/data_embed/script.js b/data_embed/script.js index 7d9c16c..285d7a7 100644 --- a/data_embed/script.js +++ b/data_embed/script.js @@ -131,7 +131,7 @@ function loadSettings(settings) { StatusPacket.disabled = !StatusCheckbox.checked; document.getElementById("beacon.gpsActive").checked = settings.beacon.gpsActive; - document.getElementById("beacon.gpsAmbiguity").checked = settings.beacon.gpsAmbiguity; + document.getElementById("beacon.ambiguityLevel").value = settings.beacon.ambiguityLevel; // Black List document.getElementById("blacklist").value = settings.blacklist; diff --git a/include/configuration.h b/include/configuration.h index 22d0bb3..609c7b1 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -51,7 +51,7 @@ public: bool statusActive; String statusPacket; bool gpsActive; - bool gpsAmbiguity; + int ambiguityLevel; }; class APRS_IS { diff --git a/src/LoRa_APRS_iGate.cpp b/src/LoRa_APRS_iGate.cpp index db14e6d..bc685a4 100644 --- a/src/LoRa_APRS_iGate.cpp +++ b/src/LoRa_APRS_iGate.cpp @@ -67,8 +67,8 @@ ___________________________________________________________________*/ #endif -String versionDate = "2025-11-29"; -String versionNumber = "3.1.4.1"; +String versionDate = "2025-11-30"; +String versionNumber = "3.1.5"; Configuration Config; WiFiClient aprsIsClient; WiFiClient mqttClient; diff --git a/src/aprs_is_utils.cpp b/src/aprs_is_utils.cpp index 1e79493..0505ea3 100644 --- a/src/aprs_is_utils.cpp +++ b/src/aprs_is_utils.cpp @@ -16,6 +16,7 @@ * along with LoRa APRS iGate. If not, see . */ +#include #include #include "configuration.h" #include "aprs_is_utils.h" @@ -236,12 +237,7 @@ namespace APRS_IS_Utils { String buildPacketToTx(const String& aprsisPacket, uint8_t packetType) { String packet = aprsisPacket; packet.trim(); - String outputPacket = Config.callsign; - outputPacket += ">APLRG1"; - if (Config.beacon.path != "") { - outputPacket += ","; - outputPacket += Config.beacon.path; - } + String outputPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path); outputPacket += ":}"; outputPacket += packet.substring(0, packet.indexOf(",")); // Callsign>Tocall outputPacket.concat(",TCPIP,"); diff --git a/src/configuration.cpp b/src/configuration.cpp index aec718b..9f763af 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -78,7 +78,7 @@ bool Configuration::writeFile() { data["beacon"]["statusPacket"] = beacon.statusPacket; data["beacon"]["gpsActive"] = beacon.gpsActive; - data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity; + data["beacon"]["ambiguityLevel"] = beacon.ambiguityLevel; data["personalNote"] = personalNote; @@ -232,7 +232,7 @@ bool Configuration::readFile() { !data["beacon"].containsKey("statusActive") || !data["beacon"].containsKey("statusPacket") || !data["beacon"].containsKey("gpsActive") || - !data["beacon"].containsKey("gpsAmbiguity")) needsRewrite = true; + !data["beacon"].containsKey("ambiguityLevel")) needsRewrite = true; beacon.latitude = data["beacon"]["latitude"] | 0.0; beacon.longitude = data["beacon"]["longitude"] | 0.0; beacon.comment = data["beacon"]["comment"] | "LoRa APRS"; @@ -246,7 +246,7 @@ bool Configuration::readFile() { beacon.statusActive = data["beacon"]["statusActive"] | false; beacon.statusPacket = data["beacon"]["statusPacket"] | ""; beacon.gpsActive = data["beacon"]["gpsActive"] | false; - beacon.gpsAmbiguity = data["beacon"]["gpsAmbiguity"] | false; + beacon.ambiguityLevel = data["beacon"]["ambiguityLevel"] | 0; if (!data.containsKey("personalNote")) needsRewrite = true; personalNote = data["personalNote"] | "personal note here"; @@ -449,7 +449,7 @@ void Configuration::setDefaultValues() { beacon.statusPacket = ""; beacon.gpsActive = false; - beacon.gpsAmbiguity = false; + beacon.ambiguityLevel = 0; personalNote = ""; diff --git a/src/gps_utils.cpp b/src/gps_utils.cpp index 6d5d128..d40a804 100644 --- a/src/gps_utils.cpp +++ b/src/gps_utils.cpp @@ -16,6 +16,7 @@ * along with LoRa APRS iGate. If not, see . */ +#include #include #include #include "configuration.h" @@ -42,70 +43,6 @@ namespace GPS_Utils { return iGateLoRaBeaconPacket; } - char *ax25_base91enc(char *s, uint8_t n, uint32_t v) { - for(s += n, *s = '\0'; n; n--) { - *(--s) = v % 91 + 33; - v /= 91; - } - return(s); - } - - float roundToTwoDecimals(float degrees) { - return round(degrees * 100) / 100; - } - - String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol) { - String encodedData = overlay; - uint32_t aprs_lat, aprs_lon; - - float processedLatitude = latitude; - float processedLongitude = longitude; - if (Config.beacon.gpsActive && Config.beacon.gpsAmbiguity) { - processedLatitude = roundToTwoDecimals(latitude); - processedLongitude = roundToTwoDecimals(longitude); - } - - aprs_lat = 900000000 - processedLatitude * 10000000; - aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615; - aprs_lon = 900000000 + processedLongitude * 10000000 / 2; - aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615; - - String Ns, Ew, helper; - if(processedLatitude < 0) { Ns = "S"; } else { Ns = "N"; } - if(processedLatitude < 0) { processedLatitude = -processedLatitude; } - - if(processedLongitude < 0) { Ew = "W"; } else { Ew = "E"; } - if(processedLongitude < 0) { processedLongitude = -processedLongitude; } - - char helper_base91[] = {"0000\0"}; - int i; - ax25_base91enc(helper_base91, 4, aprs_lat); - for (i = 0; i < 4; i++) { - encodedData += helper_base91[i]; - } - ax25_base91enc(helper_base91, 4, aprs_lon); - for (i = 0; i < 4; i++) { - encodedData += helper_base91[i]; - } - encodedData += symbol; - encodedData += " "; - encodedData += "\x47"; - return encodedData; - } - - void generateBeaconFirstPart() { - String beaconPacket = Config.callsign; - beaconPacket += ">APLRG1"; - if (Config.beacon.path.indexOf("WIDE") == 0) { - beaconPacket += ","; - beaconPacket += Config.beacon.path; - } - iGateBeaconPacket = beaconPacket; - iGateBeaconPacket += ",qAC:!"; - iGateLoRaBeaconPacket = beaconPacket; - iGateLoRaBeaconPacket += ":!"; - } - void generateBeacons() { if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) { displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000); @@ -116,9 +53,17 @@ namespace GPS_Utils { Config.digi.mode = 0; Config.backupDigiMode = false; } - generateBeaconFirstPart(); - String encodedGPS = encodeGPS(Config.beacon.latitude, Config.beacon.longitude, Config.beacon.overlay, Config.beacon.symbol); + String beaconPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path); + String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(Config.beacon.latitude, Config.beacon.longitude, 0, 0, Config.beacon.symbol, true, 0, true, Config.beacon.ambiguityLevel); + + iGateBeaconPacket = beaconPacket; + iGateBeaconPacket += ",qAC:!"; + iGateBeaconPacket += Config.beacon.overlay; iGateBeaconPacket += encodedGPS; + + iGateLoRaBeaconPacket = beaconPacket; + iGateLoRaBeaconPacket += ":="; + iGateLoRaBeaconPacket += Config.beacon.overlay; iGateLoRaBeaconPacket += encodedGPS; } @@ -126,47 +71,40 @@ namespace GPS_Utils { return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0; } + 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; + + } + String decodeEncodedGPS(const String& packet) { int indexOfExclamation = packet.indexOf(":!"); int indexOfEqual = packet.indexOf(":="); const uint8_t OFFSET = 3; // Offset for encoded data in the packet - String GPSPacket; + String infoGPS; if (indexOfExclamation > 10) { - GPSPacket = packet.substring(indexOfExclamation + OFFSET); + infoGPS = packet.substring(indexOfExclamation + OFFSET); } else if (indexOfEqual > 10) { - GPSPacket = packet.substring(indexOfEqual + OFFSET); + infoGPS = packet.substring(indexOfEqual + OFFSET); } - String encodedLatitude = GPSPacket.substring(0,4); - int Y1 = encodedLatitude[0] - 33; - int Y2 = encodedLatitude[1] - 33; - int Y3 = encodedLatitude[2] - 33; - int Y4 = encodedLatitude[3] - 33; - float decodedLatitude = 90.0 - (((Y1 * pow(91,3)) + (Y2 * pow(91,2)) + (Y3 * 91) + Y4) / 380926.0); + float decodedLatitude = APRSPacketLib::decodeBase91EncodedLatitude(infoGPS.substring(0,4)); + float decodedLongitude = APRSPacketLib::decodeBase91EncodedLongitude(infoGPS.substring(4,8)); - String encodedLongitude = GPSPacket.substring(4,8); - int X1 = encodedLongitude[0] - 33; - int X2 = encodedLongitude[1] - 33; - int X3 = encodedLongitude[2] - 33; - int X4 = encodedLongitude[3] - 33; - float decodedLongitude = -180.0 + (((X1 * pow(91,3)) + (X2 * pow(91,2)) + (X3 * 91) + X4) / 190463.0); - - distance = String(calculateDistanceTo(decodedLatitude, decodedLongitude),1); - - String decodedGPS = String(decodedLatitude,5); - decodedGPS += "N / "; - decodedGPS += String(decodedLongitude,5); - decodedGPS += "E / "; - decodedGPS += distance; - decodedGPS += "km"; - - String comment = GPSPacket.substring(12); - if (comment != "") { - decodedGPS += " / "; - decodedGPS += comment; - } - return decodedGPS; + return buildDistanceAndComment(decodedLatitude, decodedLongitude, infoGPS.substring(12)); } String getReceivedGPS(const String& packet) { @@ -195,21 +133,7 @@ namespace GPS_Utils { convertedLongitude += Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100); if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere - distance = String(calculateDistanceTo(convertedLatitude, convertedLongitude),1); - - String decodedGPS = String(convertedLatitude,5); - decodedGPS += "N / "; - decodedGPS += String(convertedLongitude,5); - decodedGPS += "E / "; - decodedGPS += distance; - decodedGPS += "km"; - - String comment = infoGPS.substring(19); - if (comment != "") { - decodedGPS += " / "; - decodedGPS += comment; - } - return decodedGPS; + return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19)); } String getDistanceAndComment(const String& packet) { diff --git a/src/utils.cpp b/src/utils.cpp index 45dbae0..e952faa 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -16,6 +16,7 @@ * along with LoRa APRS iGate. If not, see . */ +#include #include #include #include "telemetry_utils.h" @@ -71,12 +72,8 @@ String secondaryBeaconPacket; namespace Utils { void processStatus() { - String status = Config.callsign; - status.concat(">APLRG1"); - if (Config.beacon.path.indexOf("WIDE") == 0) { - status.concat(","); - status.concat(Config.beacon.path); - } + String status = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path); + if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) { delay(1000); status.concat(",qAC:>"); @@ -161,18 +158,27 @@ namespace Utils { showActiveStations(); - beaconPacket = iGateBeaconPacket; - secondaryBeaconPacket = iGateLoRaBeaconPacket; #ifdef HAS_GPS if (Config.beacon.gpsActive && Config.digi.ecoMode == 0) { GPS_Utils::getData(); if (gps.location.isUpdated() && gps.location.lat() != 0.0 && gps.location.lng() != 0.0) { - GPS_Utils::generateBeaconFirstPart(); - String encodedGPS = GPS_Utils::encodeGPS(gps.location.lat(), gps.location.lng(), Config.beacon.overlay, Config.beacon.symbol); - beaconPacket = iGateBeaconPacket + encodedGPS; - secondaryBeaconPacket = iGateLoRaBeaconPacket + encodedGPS; + String basePacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path); + String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(gps.location.lat(),gps.location.lng(), 0, 0, Config.beacon.symbol, true, 0, true, Config.beacon.ambiguityLevel); + + beaconPacket = basePacket; + beaconPacket += ",qAC:!"; + beaconPacket += Config.beacon.overlay; + beaconPacket += encodedGPS; + + secondaryBeaconPacket = basePacket; + secondaryBeaconPacket += ":="; + secondaryBeaconPacket += Config.beacon.overlay; + secondaryBeaconPacket += encodedGPS; } } + #else + beaconPacket = iGateBeaconPacket; + secondaryBeaconPacket = iGateLoRaBeaconPacket; #endif if (Config.wxsensor.active) { diff --git a/src/web_utils.cpp b/src/web_utils.cpp index 72fcf25..f8bfc46 100644 --- a/src/web_utils.cpp +++ b/src/web_utils.cpp @@ -191,7 +191,7 @@ namespace WEB_Utils { } Config.beacon.gpsActive = request->hasParam("beacon.gpsActive", true); - Config.beacon.gpsAmbiguity = request->hasParam("beacon.gpsAmbiguity", true); + Config.beacon.ambiguityLevel = getParamIntSafe("beacon.ambiguityLevel", Config.beacon.ambiguityLevel); Config.personalNote = getParamStringSafe("personalNote", Config.personalNote); diff --git a/src/wifi_utils.cpp b/src/wifi_utils.cpp index 64c1d7d..a5b8889 100644 --- a/src/wifi_utils.cpp +++ b/src/wifi_utils.cpp @@ -60,7 +60,7 @@ namespace WIFI_Utils { Serial.print(millis()); Serial.println("Reconnecting to WiFi..."); WiFi.disconnect(); - WIFI_Utils::startWiFi();//WiFi.reconnect(); + WIFI_Utils::startWiFi(); previousWiFiMillis = millis(); if (Config.backupDigiMode) {