Compare commits

...

18 Commits

Author SHA1 Message Date
Ricardo Guzman (Richonguzman) 6a4c0ef01a readme update 2025-12-01 09:38:37 -03:00
Ricardo Guzman (Richonguzman) 0bd3201ef7 AHT20 add 2025-12-01 09:37:02 -03:00
Ricardo Guzman (Richonguzman) b5d9103ea5 gps beacon fix 2025-11-30 10:47:12 -03:00
Ricardo Guzman (Richonguzman) 20a5029da8 index fix 2025-11-30 10:37:23 -03:00
Ricardo Guzman (Richonguzman) b3cc8af180 test update aprspacketlib 2025-11-30 10:15:01 -03:00
Ricardo Guzman (Richonguzman) ca16761f68 loadCallsignList update 2025-11-29 14:11:43 -03:00
Ricardo Guzman (Richonguzman) e593b2c670 version number update 2025-11-08 21:16:03 -03:00
Ricardo Guzman (Richonguzman) 08a7e0aac1 T-Beam Supreme Screen Fix 2025-11-08 21:13:57 -03:00
Ricardo Guzman (Richonguzman) 9b258c42ab checkValidCallsign update 2025-11-06 10:11:55 -03:00
richonguzman 8712122d33 raw images 2025-10-29 10:34:43 -03:00
richonguzman 9e34684627 update pdf y blob 2025-10-29 10:28:25 -03:00
richonguzman e4aa52241d sin gitattributes ahora 2025-10-29 10:11:18 -03:00
richonguzman c840ef01fa sin manual en github 2025-10-29 10:10:58 -03:00
richonguzman 98f85725f8 test con Vista Previa 2025-10-29 09:13:48 -03:00
richonguzman 10bde884b1 new gitattributes 2025-10-28 22:54:22 -03:00
richonguzman 546e4f63a4 update pdf to v1.4 2025-10-28 22:46:44 -03:00
Ricardo Guzman (Richonguzman) 87f2ec2b7b test new version pdf 20250128 2025-10-28 22:40:15 -03:00
Ricardo Guzman (Richonguzman) c9c7e24aae Merge pull request #356 from richonguzman/richonguzman-patch-15
Delete manual/LoRa_APRS_iGate_CA2RXU_Firmware_Manual.pdf
2025-10-28 22:38:23 -03:00
18 changed files with 131 additions and 211 deletions
+4 -3
View File
@@ -2,7 +2,7 @@
This firmware is for using ESP32 based boards with LoRa Modules and GPS to live in the APRS world. This firmware is for using ESP32 based boards with LoRa Modules and GPS to live in the APRS world.
![Screenshot](https://github.com/richonguzman/LoRa_APRS_iGate/blob/main/images/iGateOledScreen.jpeg) ![Screenshot](https://github.com/richonguzman/LoRa_APRS_iGate/raw/main/images/iGateOledScreen.jpeg)
__(This iGate Firmware works with all LoRa Tracker Firmwares (specially this <a href="https://github.com/richonguzman/LoRa_APRS_Tracker" target="_blank">LoRa APRS Tracker Firmware</a>))__ __(This iGate Firmware works with all LoRa Tracker Firmwares (specially this <a href="https://github.com/richonguzman/LoRa_APRS_Tracker" target="_blank">LoRa APRS Tracker Firmware</a>))__
<br /> <br />
@@ -12,13 +12,13 @@ ____________________________________________________
# <a href="https://richonguzman.github.io/lora-igate-web-flasher/installer.html" target="_blank">WEB FLASHER/INSTALLER</a> # <a href="https://richonguzman.github.io/lora-igate-web-flasher/installer.html" target="_blank">WEB FLASHER/INSTALLER</a>
# <a href="https://github.com/richonguzman/LoRa_APRS_iGate/blob/main/manual/LoRa_APRS_iGate_CA2RXU_Firmware_Manual.pdf" target="_blank">LoRa APRS iGate CA2RXU Firmware Manual</a> # <a href="https://drive.google.com/file/d/1-jafzOWis_qOaNUl4WGVcFKjh_uCJtB6/view?usp=share_link" target="_blank">LoRa APRS iGate CA2RXU Firmware Manual</a>
____________________________________________________ ____________________________________________________
## You can support this project to continue to grow: ## You can support this project to continue to grow:
[<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/github-sponsors.png">](https://github.com/sponsors/richonguzman) [<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/paypalme.png">](http://paypal.me/richonguzman) [<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/raw/main/images/github-sponsors.png">](https://github.com/sponsors/richonguzman) [<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/raw/main/images/paypalme.png">](http://paypal.me/richonguzman)
____________________________________________________ ____________________________________________________
@@ -51,6 +51,7 @@ ____________________________________________________
<br /> <br />
# Timeline (Versions): # Timeline (Versions):
- 2025-12-01 APRSPacketLib updates, AHT20 sensor added.
- 2025-10-15 APRS Bridge for TNC added. - 2025-10-15 APRS Bridge for TNC added.
- 2025-10-13 Rx and Tx Frequencies are now with fully configurable. - 2025-10-13 Rx and Tx Frequencies are now with fully configurable.
- 2025-10-13 Startup Delay to allow the Router/Modem to start WiFiAP before connecting. - 2025-10-13 Startup Delay to allow the Router/Modem to start WiFiAP before connecting.
+2 -1
View File
@@ -25,6 +25,7 @@ build_flags =
-I variants/${PIOENV} -I variants/${PIOENV}
lib_deps = lib_deps =
adafruit/Adafruit Unified Sensor @ 1.1.14 adafruit/Adafruit Unified Sensor @ 1.1.14
adafruit/Adafruit AHTX0 @ 2.0.5
adafruit/Adafruit BME280 Library @ 2.2.4 adafruit/Adafruit BME280 Library @ 2.2.4
adafruit/Adafruit BMP280 Library @ 2.6.8 adafruit/Adafruit BMP280 Library @ 2.6.8
adafruit/Adafruit BME680 Library @ 2.0.4 adafruit/Adafruit BME680 Library @ 2.0.4
@@ -37,7 +38,7 @@ lib_deps =
mathieucarbou/AsyncTCP @ 3.2.5 mathieucarbou/AsyncTCP @ 3.2.5
mathieucarbou/ESPAsyncWebServer @ 3.2.3 mathieucarbou/ESPAsyncWebServer @ 3.2.3
mikalhart/TinyGPSPlus @ 1.0.3 mikalhart/TinyGPSPlus @ 1.0.3
richonguzman/APRSPacketLib @1.0.0 richonguzman/APRSPacketLib @1.0.4
display_libs = display_libs =
adafruit/Adafruit GFX Library @ 1.11.9 adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10 adafruit/Adafruit SSD1306 @ 2.5.10
+1 -1
View File
@@ -21,7 +21,7 @@
"statusActive": false, "statusActive": false,
"statusPacket": "", "statusPacket": "",
"gpsActive": false, "gpsActive": false,
"gpsAmbiguity": false "ambiguityLevel": 0
}, },
"aprs_is": { "aprs_is": {
"active": false, "active": false,
+31 -54
View File
@@ -144,8 +144,7 @@
name="beacon.comment" name="beacon.comment"
id="beacon.comment" id="beacon.comment"
class="form-control" class="form-control"
placeholder="LoRa APRS" placeholder=""
required=""
/> />
</div> </div>
<div class="col-12 mt-3"> <div class="col-12 mt-3">
@@ -189,18 +188,10 @@
name="action.symbol" name="action.symbol"
id="action.symbol" id="action.symbol"
> >
<option value="L#"> <option value="L#">Green star with L</option>
Green star with L <option value="L_">Blue circle with L</option>
</option> <option value="L&">Black diamond with L</option>
<option value="L_"> <option value="La" selected>Red diamond with L</option>
Blue circle with L
</option>
<option value="L&">
Black diamond with L
</option>
<option value="La">
Red diamond with L
</option>
</select> </select>
</div> </div>
<div <div
@@ -583,12 +574,8 @@
name="beacon.beaconFreq" name="beacon.beaconFreq"
id="beacon.beaconFreq" id="beacon.beaconFreq"
> >
<option value="0"> <option value="0">Beacon on Rx Freq</option>
Beacon on Rx Freq <option value="1">Beacon on Tx Freq</option>
</option>
<option value="1">
Beacon on Tx Freq
</option>
</select> </select>
</div> </div>
</div> </div>
@@ -615,6 +602,23 @@
</span> </span>
</div> </div>
</div> </div>
<div class="col-6">
<label
for="beacon.ambiguityLevel"
class="form-label"
>APRS Position Ambiguity</label
>
<select
class="form-select form-select"
name="beacon.ambiguityLevel"
id="beacon.ambiguityLevel"
>
<option value="0" selected>No Ambiguity</option>
<option value="1">~110 m forced Ambiguity</option>
<option value="2">~1.1 km forced Ambiguity</option>
<option value="3">~11 km forced Ambiguity</option>
</select>
</div>
</div> </div>
<div class="col-12 mt-3"> <div class="col-12 mt-3">
<div class="form-check form-switch"> <div class="form-check form-switch">
@@ -631,21 +635,6 @@
</label> </label>
</div> </div>
</div> </div>
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.gpsAmbiguity"
id="beacon.gpsAmbiguity"
class="form-check-input"
/>
<label
for="beacon.gpsAmbiguity"
class="form-label"
>Send Real-GPS Beacon with Ambiguity <small>(~ 1 Km of Random Error)</small>
</label>
</div>
</div>
</div> </div>
</div> </div>
<hr> <hr>
@@ -667,7 +656,7 @@
</svg> </svg>
Black List Black List
</h5> </h5>
<small>Add Callsigns with space between them to Blacklist them (* wild card allowed)</small> <small>Add Callsigns with space between them to Blacklist (* wildcard allowed)</small>
</div> </div>
<div class="col-9"> <div class="col-9">
<div class="row"> <div class="row">
@@ -723,15 +712,9 @@
name="digi.mode" name="digi.mode"
id="digi.mode" id="digi.mode"
> >
<option value="0"> <option value="0" selected>OFF</option>
OFF <option value="2">WIDE1 (fill-in) Digi</option>
</option> <option value="3">WIDE2 (+WIDE1) Digi</option>
<option value="2">
WIDE1 (fill-in) Digi
</option>
<option value="3">
WIDE2 (+WIDE1) Digi
</option>
</select> </select>
</div> </div>
<div class="col-12 mt-3"> <div class="col-12 mt-3">
@@ -748,15 +731,9 @@
name="digi.ecoMode" name="digi.ecoMode"
id="digi.ecoMode" id="digi.ecoMode"
> >
<option value="0"> <option value="0" selected>OFF (Normal Mode - WiFiAP and Serial Output enabled)</option>
OFF (Normal Mode - WiFiAP and Serial Output enabled) <option value="1">Ultra Eco Mode (Sleep till Packet Rx (WiFiAP/WebUI & Display disabled))</option>
</option> <option value="2">OFF (Normal Mode - WiFiAP disabled but Serial Output still enabled)</option>
<option value="1">
Ultra Eco Mode (Sleep till Packet Rx (WiFiAP/WebUI & Display disabled))
</option>
<option value="2">
OFF (Normal Mode - WiFiAP disabled but Serial Output still enabled)
</option>
</select> </select>
</div> </div>
</div> </div>
+1 -1
View File
@@ -131,7 +131,7 @@ function loadSettings(settings) {
StatusPacket.disabled = !StatusCheckbox.checked; StatusPacket.disabled = !StatusCheckbox.checked;
document.getElementById("beacon.gpsActive").checked = settings.beacon.gpsActive; 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 // Black List
document.getElementById("blacklist").value = settings.blacklist; document.getElementById("blacklist").value = settings.blacklist;
+1 -1
View File
@@ -51,7 +51,7 @@ public:
bool statusActive; bool statusActive;
String statusPacket; String statusPacket;
bool gpsActive; bool gpsActive;
bool gpsAmbiguity; int ambiguityLevel;
}; };
class APRS_IS { class APRS_IS {
+1
View File
@@ -20,6 +20,7 @@
#define WX_UTILS_H_ #define WX_UTILS_H_
#include <Adafruit_Sensor.h> #include <Adafruit_Sensor.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_BME280.h> #include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h> #include <Adafruit_BMP280.h>
#include <Adafruit_BME680.h> #include <Adafruit_BME680.h>
+2 -2
View File
@@ -67,8 +67,8 @@ ___________________________________________________________________*/
#endif #endif
String versionDate = "2025-10-21"; String versionDate = "2025-12-01";
String versionNumber = "3.1.4"; String versionNumber = "3.1.5";
Configuration Config; Configuration Config;
WiFiClient aprsIsClient; WiFiClient aprsIsClient;
WiFiClient mqttClient; WiFiClient mqttClient;
+2 -6
View File
@@ -16,6 +16,7 @@
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>. * along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <APRSPacketLib.h>
#include <WiFi.h> #include <WiFi.h>
#include "configuration.h" #include "configuration.h"
#include "aprs_is_utils.h" #include "aprs_is_utils.h"
@@ -236,12 +237,7 @@ namespace APRS_IS_Utils {
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType) { String buildPacketToTx(const String& aprsisPacket, uint8_t packetType) {
String packet = aprsisPacket; String packet = aprsisPacket;
packet.trim(); packet.trim();
String outputPacket = Config.callsign; String outputPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
outputPacket += ">APLRG1";
if (Config.beacon.path != "") {
outputPacket += ",";
outputPacket += Config.beacon.path;
}
outputPacket += ":}"; outputPacket += ":}";
outputPacket += packet.substring(0, packet.indexOf(",")); // Callsign>Tocall outputPacket += packet.substring(0, packet.indexOf(",")); // Callsign>Tocall
outputPacket.concat(",TCPIP,"); outputPacket.concat(",TCPIP,");
+4 -4
View File
@@ -78,7 +78,7 @@ bool Configuration::writeFile() {
data["beacon"]["statusPacket"] = beacon.statusPacket; data["beacon"]["statusPacket"] = beacon.statusPacket;
data["beacon"]["gpsActive"] = beacon.gpsActive; data["beacon"]["gpsActive"] = beacon.gpsActive;
data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity; data["beacon"]["ambiguityLevel"] = beacon.ambiguityLevel;
data["personalNote"] = personalNote; data["personalNote"] = personalNote;
@@ -232,7 +232,7 @@ bool Configuration::readFile() {
!data["beacon"].containsKey("statusActive") || !data["beacon"].containsKey("statusActive") ||
!data["beacon"].containsKey("statusPacket") || !data["beacon"].containsKey("statusPacket") ||
!data["beacon"].containsKey("gpsActive") || !data["beacon"].containsKey("gpsActive") ||
!data["beacon"].containsKey("gpsAmbiguity")) needsRewrite = true; !data["beacon"].containsKey("ambiguityLevel")) needsRewrite = true;
beacon.latitude = data["beacon"]["latitude"] | 0.0; beacon.latitude = data["beacon"]["latitude"] | 0.0;
beacon.longitude = data["beacon"]["longitude"] | 0.0; beacon.longitude = data["beacon"]["longitude"] | 0.0;
beacon.comment = data["beacon"]["comment"] | "LoRa APRS"; beacon.comment = data["beacon"]["comment"] | "LoRa APRS";
@@ -246,7 +246,7 @@ bool Configuration::readFile() {
beacon.statusActive = data["beacon"]["statusActive"] | false; beacon.statusActive = data["beacon"]["statusActive"] | false;
beacon.statusPacket = data["beacon"]["statusPacket"] | ""; beacon.statusPacket = data["beacon"]["statusPacket"] | "";
beacon.gpsActive = data["beacon"]["gpsActive"] | false; beacon.gpsActive = data["beacon"]["gpsActive"] | false;
beacon.gpsAmbiguity = data["beacon"]["gpsAmbiguity"] | false; beacon.ambiguityLevel = data["beacon"]["ambiguityLevel"] | 0;
if (!data.containsKey("personalNote")) needsRewrite = true; if (!data.containsKey("personalNote")) needsRewrite = true;
personalNote = data["personalNote"] | "personal note here"; personalNote = data["personalNote"] | "personal note here";
@@ -449,7 +449,7 @@ void Configuration::setDefaultValues() {
beacon.statusPacket = ""; beacon.statusPacket = "";
beacon.gpsActive = false; beacon.gpsActive = false;
beacon.gpsAmbiguity = false; beacon.ambiguityLevel = 0;
personalNote = ""; personalNote = "";
+1 -1
View File
@@ -107,7 +107,7 @@ void displaySetup() {
#endif #endif
#if defined(TTGO_T_Beam_S3_SUPREME_V3) #if defined(TTGO_T_Beam_S3_SUPREME_V3)
if (!display.begin(0x3c, false)) { if (display.begin(0x3c, false)) {
displayFound = true; displayFound = true;
if (Config.display.turn180) display.setRotation(2); if (Config.display.turn180) display.setRotation(2);
display.clearDisplay(); display.clearDisplay();
+36 -112
View File
@@ -16,6 +16,7 @@
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>. * along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <APRSPacketLib.h>
#include <TinyGPS++.h> #include <TinyGPS++.h>
#include <WiFi.h> #include <WiFi.h>
#include "configuration.h" #include "configuration.h"
@@ -42,70 +43,6 @@ namespace GPS_Utils {
return iGateLoRaBeaconPacket; 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() { void generateBeacons() {
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) { if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000); displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000);
@@ -116,9 +53,17 @@ namespace GPS_Utils {
Config.digi.mode = 0; Config.digi.mode = 0;
Config.backupDigiMode = false; Config.backupDigiMode = false;
} }
generateBeaconFirstPart(); String beaconPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
String encodedGPS = encodeGPS(Config.beacon.latitude, Config.beacon.longitude, Config.beacon.overlay, Config.beacon.symbol); String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(Config.beacon.latitude, Config.beacon.longitude, 0, 0, Config.beacon.symbol, false, 0, true, Config.beacon.ambiguityLevel);
iGateBeaconPacket = beaconPacket;
iGateBeaconPacket += ",qAC:!";
iGateBeaconPacket += Config.beacon.overlay;
iGateBeaconPacket += encodedGPS; iGateBeaconPacket += encodedGPS;
iGateLoRaBeaconPacket = beaconPacket;
iGateLoRaBeaconPacket += ":=";
iGateLoRaBeaconPacket += Config.beacon.overlay;
iGateLoRaBeaconPacket += encodedGPS; iGateLoRaBeaconPacket += encodedGPS;
} }
@@ -126,47 +71,40 @@ namespace GPS_Utils {
return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0; 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) { String decodeEncodedGPS(const String& packet) {
int indexOfExclamation = packet.indexOf(":!"); int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":="); int indexOfEqual = packet.indexOf(":=");
const uint8_t OFFSET = 3; // Offset for encoded data in the packet const uint8_t OFFSET = 3; // Offset for encoded data in the packet
String GPSPacket; String infoGPS;
if (indexOfExclamation > 10) { if (indexOfExclamation > 10) {
GPSPacket = packet.substring(indexOfExclamation + OFFSET); infoGPS = packet.substring(indexOfExclamation + OFFSET);
} else if (indexOfEqual > 10) { } else if (indexOfEqual > 10) {
GPSPacket = packet.substring(indexOfEqual + OFFSET); infoGPS = packet.substring(indexOfEqual + OFFSET);
} }
String encodedLatitude = GPSPacket.substring(0,4); float decodedLatitude = APRSPacketLib::decodeBase91EncodedLatitude(infoGPS.substring(0,4));
int Y1 = encodedLatitude[0] - 33; float decodedLongitude = APRSPacketLib::decodeBase91EncodedLongitude(infoGPS.substring(4,8));
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);
String encodedLongitude = GPSPacket.substring(4,8); return buildDistanceAndComment(decodedLatitude, decodedLongitude, infoGPS.substring(12));
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;
} }
String getReceivedGPS(const String& packet) { String getReceivedGPS(const String& packet) {
@@ -195,21 +133,7 @@ namespace GPS_Utils {
convertedLongitude += Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100); convertedLongitude += Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100);
if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere
distance = String(calculateDistanceTo(convertedLatitude, convertedLongitude),1); return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));
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;
} }
String getDistanceAndComment(const String& packet) { String getDistanceAndComment(const String& packet) {
+1 -1
View File
@@ -204,7 +204,7 @@ namespace LoRa_Utils {
if (packet != "") { if (packet != "") {
String sender = packet.substring(3, packet.indexOf(">")); String sender = packet.substring(3, packet.indexOf(">"));
if (packet.substring(0,3) == "\x3c\xff\x01" && !STATION_Utils::isBlacklisted(sender)){ // avoid processing BlackListed stations if (packet.substring(0,3) == "\x3c\xff\x01" && !STATION_Utils::isBlacklisted(sender)) { // avoid processing BlackListed stations
rssi = radio.getRSSI(); rssi = radio.getRSSI();
snr = radio.getSNR(); snr = radio.getSNR();
freqError = radio.getFrequencyError(); freqError = radio.getFrequencyError();
+4 -4
View File
@@ -57,7 +57,7 @@ bool packetIsBeacon = false;
namespace STATION_Utils { namespace STATION_Utils {
std::vector<String> loadCallSignList(const String& list) { std::vector<String> loadCallsignList(const String& list) {
std::vector<String> loadedList; std::vector<String> loadedList;
String callsigns = list; String callsigns = list;
@@ -77,12 +77,12 @@ namespace STATION_Utils {
} }
void loadBlacklistAndManagers() { void loadBlacklistAndManagers() {
blacklist = loadCallSignList(Config.blacklist); blacklist = loadCallsignList(Config.blacklist);
managers = loadCallSignList(Config.remoteManagement.managers); managers = loadCallsignList(Config.remoteManagement.managers);
} }
bool checkCallsignList(const std::vector<String>& list, const String& callsign) { bool checkCallsignList(const std::vector<String>& list, const String& callsign) {
for (int i = 0; i < list.size(); i++) { for (size_t i = 0; i < list.size(); i++) {
int wildcardIndex = list[i].indexOf("*"); int wildcardIndex = list[i].indexOf("*");
if (wildcardIndex >= 0) { if (wildcardIndex >= 0) {
String wildcard = list[i].substring(0, wildcardIndex); String wildcard = list[i].substring(0, wildcardIndex);
+19 -12
View File
@@ -16,6 +16,7 @@
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>. * along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <APRSPacketLib.h>
#include <TinyGPS++.h> #include <TinyGPS++.h>
#include <WiFi.h> #include <WiFi.h>
#include "telemetry_utils.h" #include "telemetry_utils.h"
@@ -71,12 +72,8 @@ String secondaryBeaconPacket;
namespace Utils { namespace Utils {
void processStatus() { void processStatus() {
String status = Config.callsign; String status = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
status.concat(">APLRG1");
if (Config.beacon.path.indexOf("WIDE") == 0) {
status.concat(",");
status.concat(Config.beacon.path);
}
if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) { if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) {
delay(1000); delay(1000);
status.concat(",qAC:>"); status.concat(",qAC:>");
@@ -161,18 +158,27 @@ namespace Utils {
showActiveStations(); showActiveStations();
beaconPacket = iGateBeaconPacket;
secondaryBeaconPacket = iGateLoRaBeaconPacket;
#ifdef HAS_GPS #ifdef HAS_GPS
if (Config.beacon.gpsActive && Config.digi.ecoMode == 0) { if (Config.beacon.gpsActive && Config.digi.ecoMode == 0) {
GPS_Utils::getData(); GPS_Utils::getData();
if (gps.location.isUpdated() && gps.location.lat() != 0.0 && gps.location.lng() != 0.0) { if (gps.location.isUpdated() && gps.location.lat() != 0.0 && gps.location.lng() != 0.0) {
GPS_Utils::generateBeaconFirstPart(); String basePacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
String encodedGPS = GPS_Utils::encodeGPS(gps.location.lat(), gps.location.lng(), Config.beacon.overlay, Config.beacon.symbol); String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(gps.location.lat(),gps.location.lng(), 0, 0, Config.beacon.symbol, false, 0, true, Config.beacon.ambiguityLevel);
beaconPacket = iGateBeaconPacket + encodedGPS;
secondaryBeaconPacket = iGateLoRaBeaconPacket + encodedGPS; 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 #endif
if (Config.wxsensor.active) { if (Config.wxsensor.active) {
@@ -402,6 +408,7 @@ namespace Utils {
cleanCallsign = callsign.substring(0, callsign.indexOf("-")); cleanCallsign = callsign.substring(0, callsign.indexOf("-"));
String ssid = callsign.substring(callsign.indexOf("-") + 1); String ssid = callsign.substring(callsign.indexOf("-") + 1);
if (ssid.indexOf("-") != -1 || ssid.length() > 2) return false; if (ssid.indexOf("-") != -1 || ssid.length() > 2) return false;
if (ssid.length() == 2 && ssid[0] == '0') return false;
for (int i = 0; i < ssid.length(); i++) { for (int i = 0; i < ssid.length(); i++) {
if (!isAlphaNumeric(ssid[i])) return false; if (!isAlphaNumeric(ssid[i])) return false;
} }
+1 -1
View File
@@ -191,7 +191,7 @@ namespace WEB_Utils {
} }
Config.beacon.gpsActive = request->hasParam("beacon.gpsActive", true); 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); Config.personalNote = getParamStringSafe("personalNote", Config.personalNote);
+1 -1
View File
@@ -60,7 +60,7 @@ namespace WIFI_Utils {
Serial.print(millis()); Serial.print(millis());
Serial.println("Reconnecting to WiFi..."); Serial.println("Reconnecting to WiFi...");
WiFi.disconnect(); WiFi.disconnect();
WIFI_Utils::startWiFi();//WiFi.reconnect(); WIFI_Utils::startWiFi();
previousWiFiMillis = millis(); previousWiFiMillis = millis();
if (Config.backupDigiMode) { if (Config.backupDigiMode) {
+19 -6
View File
@@ -42,6 +42,7 @@ float newHum, newTemp, newPress, newGas;
Adafruit_BME280 bme280; Adafruit_BME280 bme280;
Adafruit_AHTX0 aht20;
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) #if defined(HELTEC_V3) || defined(HELTEC_V3_2)
Adafruit_BMP280 bmp280(&Wire1); Adafruit_BMP280 bmp280(&Wire1);
Adafruit_Si7021 si7021 = Adafruit_Si7021(); Adafruit_Si7021 si7021 = Adafruit_Si7021();
@@ -119,6 +120,10 @@ namespace WX_Utils {
Serial.println("BMP280 sensor found"); Serial.println("BMP280 sensor found");
wxModuleType = 2; wxModuleType = 2;
wxModuleFound = true; wxModuleFound = true;
if (aht20.begin()) {
Serial.println("AHT20 sensor found");
if (wxModuleType == 2) wxModuleType = 6;
}
} }
} }
} else if (wxModuleAddress == 0x40) { } else if (wxModuleAddress == 0x40) {
@@ -127,7 +132,7 @@ namespace WX_Utils {
wxModuleType = 4; wxModuleType = 4;
wxModuleFound = true; wxModuleFound = true;
} }
} }
#ifdef LIGHTGATEWAY_PLUS_1_0 #ifdef LIGHTGATEWAY_PLUS_1_0
else if (wxModuleAddress == 0x70) { else if (wxModuleAddress == 0x70) {
if (shtc3.begin()) { if (shtc3.begin()) {
@@ -273,7 +278,15 @@ namespace WX_Utils {
newPress = 0; newPress = 0;
#endif #endif
break; break;
} case 6: // BMP280 + AHT20
bmp280.takeForcedMeasurement();
newTemp = bmp280.readTemperature();
newPress = (bmp280.readPressure() / 100.0F);
sensors_event_t humidity, temp;
aht20.getEvent(&humidity, &temp);
newHum = humidity.relative_humidity;
break;
}
if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) { if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) {
Serial.println("BME/BMP/Si7021 Module data failed"); Serial.println("BME/BMP/Si7021 Module data failed");
@@ -281,16 +294,16 @@ namespace WX_Utils {
return ".../...g...t..."; return ".../...g...t...";
} else { } else {
String tempStr = generateTempString(((newTemp + Config.wxsensor.temperatureCorrection) * 1.8) + 32); String tempStr = generateTempString(((newTemp + Config.wxsensor.temperatureCorrection) * 1.8) + 32);
String humStr; String humStr;
if (wxModuleType == 1 || wxModuleType == 3 || wxModuleType == 4 || wxModuleType == 5) { if (wxModuleType == 1 || wxModuleType == 3 || wxModuleType == 4 || wxModuleType == 5 || wxModuleType == 6) {
humStr = generateHumString(newHum); humStr = generateHumString(newHum);
} else if (wxModuleType == 2) { } else if (wxModuleType == 2) {
humStr = ".."; humStr = "..";
} }
String presStr = (wxModuleType == 4 || wxModuleType == 5) String presStr = (wxModuleType == 4 || wxModuleType == 5)
? "....." ? "....."
: generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR); : generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR);
fifthLine = "BME-> "; fifthLine = "BME-> ";