forked from iarv/LoRa_APRS_iGate
Compare commits
18 Commits
decodingFi
...
Tactical
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76fe27a0ab | ||
|
|
da80391921 | ||
|
|
d638093dbf | ||
|
|
66a5f03c12 | ||
|
|
ce8cf3a2fe | ||
|
|
4b45b90c88 | ||
|
|
dbe980a081 | ||
|
|
bb3d59a20d | ||
|
|
fe590b41b0 | ||
|
|
3f76005949 | ||
|
|
6d95231b9c | ||
|
|
81692010cf | ||
|
|
50b738d04b | ||
|
|
026d6b2eeb | ||
|
|
fe705519cb | ||
|
|
1fa74b8697 | ||
|
|
a3794085b4 | ||
|
|
0a898a40e6 |
@@ -51,6 +51,8 @@ ____________________________________________________
|
|||||||
<br />
|
<br />
|
||||||
|
|
||||||
# Timeline (Versions):
|
# Timeline (Versions):
|
||||||
|
- 2026-01-07 Tactical Callsign added.
|
||||||
|
- 2026-01-05 Heltec V4 support added.
|
||||||
- 2025-12-22 Heltec Wireless Paper V1.2 and VisionMaster E290 Added. Thanks HA5SZI.
|
- 2025-12-22 Heltec Wireless Paper V1.2 and VisionMaster E290 Added. Thanks HA5SZI.
|
||||||
- 2025-12-18 TCXO and packet decoding updates.
|
- 2025-12-18 TCXO and packet decoding updates.
|
||||||
- 2025-12-01 APRSPacketLib updates, AHT20 sensor added, INA219 support added.
|
- 2025-12-01 APRSPacketLib updates, AHT20 sensor added, INA219 support added.
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ lib_deps =
|
|||||||
adafruit/Adafruit INA219 @ 1.2.3
|
adafruit/Adafruit INA219 @ 1.2.3
|
||||||
adafruit/Adafruit Si7021 Library @ 1.5.3
|
adafruit/Adafruit Si7021 Library @ 1.5.3
|
||||||
arduino-libraries/NTPClient @ 3.2.1
|
arduino-libraries/NTPClient @ 3.2.1
|
||||||
ayushsharma82/ElegantOTA @ 3.1.5
|
ayushsharma82/ElegantOTA @ 3.1.7
|
||||||
bblanchon/ArduinoJson @ 6.21.3
|
bblanchon/ArduinoJson @ 6.21.3
|
||||||
jgromes/RadioLib @ 7.1.0
|
jgromes/RadioLib @ 7.1.0
|
||||||
knolleary/PubSubClient @ 2.8
|
knolleary/PubSubClient @ 2.8
|
||||||
mathieucarbou/AsyncTCP @ 3.2.5
|
ESP32Async/AsyncTCP @ 3.4.9
|
||||||
mathieucarbou/ESPAsyncWebServer @ 3.2.3
|
ESP32Async/ESPAsyncWebServer @ 3.9.3
|
||||||
mikalhart/TinyGPSPlus @ 1.0.3
|
mikalhart/TinyGPSPlus @ 1.0.3
|
||||||
richonguzman/APRSPacketLib @ 1.0.4
|
richonguzman/APRSPacketLib @ 1.0.4
|
||||||
display_libs =
|
display_libs =
|
||||||
|
|||||||
@@ -119,7 +119,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-lg-9 col-sm-12">
|
<div class="col-lg-9 col-sm-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-6">
|
||||||
<label for="callsign" class="form-label"
|
<label for="callsign" class="form-label"
|
||||||
>Callsign - SSID</label
|
>Callsign - SSID</label
|
||||||
>
|
>
|
||||||
@@ -133,6 +133,19 @@
|
|||||||
oninput="this.value = this.value.toUpperCase();"
|
oninput="this.value = this.value.toUpperCase();"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-6">
|
||||||
|
<label for="tacticalCallsign" class="form-label"
|
||||||
|
>Tactical Callsign</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="tacticalCallsign"
|
||||||
|
id="tacticalCallsign"
|
||||||
|
class="form-control"
|
||||||
|
placeholder=""
|
||||||
|
oninput="this.value = this.value.toUpperCase();"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="col-12 mt-3">
|
<div class="col-12 mt-3">
|
||||||
<label
|
<label
|
||||||
for="beacon.comment"
|
for="beacon.comment"
|
||||||
@@ -158,7 +171,7 @@
|
|||||||
name="beacon.path"
|
name="beacon.path"
|
||||||
id="beacon.path"
|
id="beacon.path"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder="We prefer WIDE1-1"
|
placeholder="WIDE1-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8 mt-3">
|
<div class="col-8 mt-3">
|
||||||
@@ -591,11 +604,11 @@
|
|||||||
type="number"
|
type="number"
|
||||||
name="beacon.interval"
|
name="beacon.interval"
|
||||||
id="beacon.interval"
|
id="beacon.interval"
|
||||||
placeholder="15"
|
|
||||||
class="form-control"
|
class="form-control"
|
||||||
required=""
|
value="15"
|
||||||
|
min="10"
|
||||||
step="1"
|
step="1"
|
||||||
min="15"
|
required
|
||||||
/>
|
/>
|
||||||
<span class="input-group-text"
|
<span class="input-group-text"
|
||||||
>minutes
|
>minutes
|
||||||
@@ -853,7 +866,9 @@
|
|||||||
id="lora.rxSpreadingFactor"
|
id="lora.rxSpreadingFactor"
|
||||||
required=""
|
required=""
|
||||||
>
|
>
|
||||||
<option value="7">SF7 - Lowest battery usage</option>
|
<option value="5">SF5 - Lowest battery usage</option>
|
||||||
|
<option value="6">SF6</option>
|
||||||
|
<option value="7">SF7</option>
|
||||||
<option value="8">SF8</option>
|
<option value="8">SF8</option>
|
||||||
<option value="9">SF9</option>
|
<option value="9">SF9</option>
|
||||||
<option value="10">SF10</option>
|
<option value="10">SF10</option>
|
||||||
@@ -873,7 +888,9 @@
|
|||||||
id="lora.txSpreadingFactor"
|
id="lora.txSpreadingFactor"
|
||||||
required=""
|
required=""
|
||||||
>
|
>
|
||||||
<option value="7">SF7 - Lowest battery usage</option>
|
<option value="5">SF5 - Lowest battery usage</option>
|
||||||
|
<option value="6">SF6</option>
|
||||||
|
<option value="7">SF7</option>
|
||||||
<option value="8">SF8</option>
|
<option value="8">SF8</option>
|
||||||
<option value="9">SF9</option>
|
<option value="9">SF9</option>
|
||||||
<option value="10">SF10</option>
|
<option value="10">SF10</option>
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ function loadSettings(settings) {
|
|||||||
currentSettings = settings;
|
currentSettings = settings;
|
||||||
// General
|
// General
|
||||||
document.getElementById("callsign").value = settings.callsign;
|
document.getElementById("callsign").value = settings.callsign;
|
||||||
|
document.getElementById("tacticalCallsign").value = settings.tacticalCallsign;
|
||||||
document.getElementById("beacon.comment").value = settings.beacon.comment;
|
document.getElementById("beacon.comment").value = settings.beacon.comment;
|
||||||
document.getElementById("beacon.path").value = settings.beacon.path;
|
document.getElementById("beacon.path").value = settings.beacon.path;
|
||||||
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
|
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ public:
|
|||||||
class Configuration {
|
class Configuration {
|
||||||
public:
|
public:
|
||||||
String callsign;
|
String callsign;
|
||||||
|
String tacticalCallsign;
|
||||||
int rememberStationTime;
|
int rememberStationTime;
|
||||||
bool backupDigiMode;
|
bool backupDigiMode;
|
||||||
bool rebootMode;
|
bool rebootMode;
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ ___________________________________________________________________*/
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
String versionDate = "2025-12-28";
|
String versionDate = "2026-01-11";
|
||||||
String versionNumber = "3.1.6.3";
|
String versionNumber = "3.1.7.1";
|
||||||
Configuration Config;
|
Configuration Config;
|
||||||
WiFiClient aprsIsClient;
|
WiFiClient aprsIsClient;
|
||||||
WiFiClient mqttClient;
|
WiFiClient mqttClient;
|
||||||
|
|||||||
@@ -274,6 +274,29 @@ namespace APRS_IS_Utils {
|
|||||||
return outputPacket;
|
return outputPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processAckMessage(const String& sender, const String& message) {
|
||||||
|
String ackPacket = Config.callsign;
|
||||||
|
ackPacket += ">APLRG1,TCPIP,qAC::";
|
||||||
|
|
||||||
|
String senderCallsign = sender;
|
||||||
|
for (int i = sender.length(); i < 9; i++) {
|
||||||
|
senderCallsign += ' ';
|
||||||
|
}
|
||||||
|
ackPacket += senderCallsign;
|
||||||
|
ackPacket += ":";
|
||||||
|
|
||||||
|
String ackMessage = "ack";
|
||||||
|
ackMessage += message.substring(message.indexOf("{") + 1);
|
||||||
|
ackMessage.trim();
|
||||||
|
ackPacket += ackMessage;
|
||||||
|
|
||||||
|
#ifdef HAS_A7670
|
||||||
|
A7670_Utils::uploadToAPRSIS(ackPacket);
|
||||||
|
#else
|
||||||
|
upload(ackPacket);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void processAPRSISPacket(const String& packet) {
|
void processAPRSISPacket(const String& packet) {
|
||||||
if (!passcodeValid && packet.indexOf(Config.callsign) != -1) {
|
if (!passcodeValid && packet.indexOf(Config.callsign) != -1) {
|
||||||
if (packet.indexOf("unverified") != -1 ) {
|
if (packet.indexOf("unverified") != -1 ) {
|
||||||
@@ -294,38 +317,19 @@ namespace APRS_IS_Utils {
|
|||||||
if (Addressee == Config.callsign) { // its for me!
|
if (Addressee == Config.callsign) { // its for me!
|
||||||
String receivedMessage;
|
String receivedMessage;
|
||||||
if (AddresseeAndMessage.indexOf("{") > 0) { // ack?
|
if (AddresseeAndMessage.indexOf("{") > 0) { // ack?
|
||||||
String ackMessage = "ack";
|
processAckMessage(Sender, AddresseeAndMessage);
|
||||||
ackMessage += AddresseeAndMessage.substring(AddresseeAndMessage.indexOf("{") + 1);
|
|
||||||
ackMessage.trim();
|
|
||||||
delay(4000);
|
|
||||||
for (int i = Sender.length(); i < 9; i++) {
|
|
||||||
Sender += ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
String ackPacket = Config.callsign;
|
|
||||||
ackPacket += ">APLRG1,TCPIP,qAC::";
|
|
||||||
ackPacket += Sender;
|
|
||||||
ackPacket += ":";
|
|
||||||
ackPacket += ackMessage;
|
|
||||||
#ifdef HAS_A7670
|
|
||||||
A7670_Utils::uploadToAPRSIS(ackPacket);
|
|
||||||
#else
|
|
||||||
upload(ackPacket);
|
|
||||||
#endif
|
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1, AddresseeAndMessage.indexOf("{"));
|
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1, AddresseeAndMessage.indexOf("{"));
|
||||||
} else {
|
} else {
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1);
|
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1);
|
||||||
}
|
}
|
||||||
if (receivedMessage.indexOf("?") == 0) {
|
if (receivedMessage.indexOf("?") == 0) {
|
||||||
Utils::println("Rx Query (APRS-IS) : " + packet);
|
Utils::println("Rx Query (APRS-IS) : " + packet);
|
||||||
Sender.trim();
|
|
||||||
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false);
|
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false);
|
||||||
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
||||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||||
displayToggle(true);
|
displayToggle(true);
|
||||||
}
|
}
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
delay(500);
|
|
||||||
#ifdef HAS_A7670
|
#ifdef HAS_A7670
|
||||||
A7670_Utils::uploadToAPRSIS(queryAnswer);
|
A7670_Utils::uploadToAPRSIS(queryAnswer);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ bool Configuration::writeFile() {
|
|||||||
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
|
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
|
||||||
|
|
||||||
callsign.trim();
|
callsign.trim();
|
||||||
callsign.toUpperCase();
|
|
||||||
data["callsign"] = callsign;
|
data["callsign"] = callsign;
|
||||||
|
tacticalCallsign.trim();
|
||||||
|
data["tacticalCallsign"] = tacticalCallsign;
|
||||||
|
|
||||||
data["aprs_is"]["active"] = aprs_is.active;
|
data["aprs_is"]["active"] = aprs_is.active;
|
||||||
data["aprs_is"]["passcode"] = aprs_is.passcode;
|
data["aprs_is"]["passcode"] = aprs_is.passcode;
|
||||||
@@ -92,15 +93,31 @@ bool Configuration::writeFile() {
|
|||||||
|
|
||||||
data["lora"]["rxActive"] = loramodule.rxActive;
|
data["lora"]["rxActive"] = loramodule.rxActive;
|
||||||
data["lora"]["rxFreq"] = loramodule.rxFreq;
|
data["lora"]["rxFreq"] = loramodule.rxFreq;
|
||||||
data["lora"]["rxSpreadingFactor"] = loramodule.rxSpreadingFactor;
|
|
||||||
data["lora"]["rxCodingRate4"] = loramodule.rxCodingRate4;
|
data["lora"]["rxCodingRate4"] = loramodule.rxCodingRate4;
|
||||||
data["lora"]["rxSignalBandwidth"] = loramodule.rxSignalBandwidth;
|
data["lora"]["rxSignalBandwidth"] = loramodule.rxSignalBandwidth;
|
||||||
data["lora"]["txActive"] = loramodule.txActive;
|
data["lora"]["txActive"] = loramodule.txActive;
|
||||||
data["lora"]["txFreq"] = loramodule.txFreq;
|
data["lora"]["txFreq"] = loramodule.txFreq;
|
||||||
data["lora"]["txSpreadingFactor"] = loramodule.txSpreadingFactor;
|
|
||||||
data["lora"]["txCodingRate4"] = loramodule.txCodingRate4;
|
data["lora"]["txCodingRate4"] = loramodule.txCodingRate4;
|
||||||
data["lora"]["txSignalBandwidth"] = loramodule.txSignalBandwidth;
|
data["lora"]["txSignalBandwidth"] = loramodule.txSignalBandwidth;
|
||||||
data["lora"]["power"] = loramodule.power;
|
data["lora"]["power"] = loramodule.power;
|
||||||
|
|
||||||
|
int rxSpreadingFactor = loramodule.rxSpreadingFactor;
|
||||||
|
int txSpreadingFactor = loramodule.txSpreadingFactor;
|
||||||
|
#if defined(HAS_SX1276) || defined(HAS_SX1278)
|
||||||
|
const int minSF = 6, maxSF = 12;
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SX1262) || defined(HAS_SX1268)
|
||||||
|
const int minSF = 5, maxSF = 12;
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_LLCC68)
|
||||||
|
const int minSF = 5, maxSF = 11;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rxSpreadingFactor = (rxSpreadingFactor < minSF) ? minSF : (rxSpreadingFactor > maxSF) ? maxSF : rxSpreadingFactor;
|
||||||
|
txSpreadingFactor = (txSpreadingFactor < minSF) ? minSF : (txSpreadingFactor > maxSF) ? maxSF : txSpreadingFactor;
|
||||||
|
|
||||||
|
data["lora"]["rxSpreadingFactor"] = rxSpreadingFactor;
|
||||||
|
data["lora"]["txSpreadingFactor"] = txSpreadingFactor;
|
||||||
|
|
||||||
data["display"]["alwaysOn"] = display.alwaysOn;
|
data["display"]["alwaysOn"] = display.alwaysOn;
|
||||||
data["display"]["timeout"] = display.timeout;
|
data["display"]["timeout"] = display.timeout;
|
||||||
@@ -204,6 +221,8 @@ bool Configuration::readFile() {
|
|||||||
|
|
||||||
if (!data.containsKey("callsign")) needsRewrite = true;
|
if (!data.containsKey("callsign")) needsRewrite = true;
|
||||||
callsign = data["callsign"] | "NOCALL-10";
|
callsign = data["callsign"] | "NOCALL-10";
|
||||||
|
if (!data.containsKey("tacticalCallsign")) needsRewrite = true;
|
||||||
|
tacticalCallsign = data["tacticalCallsign"] | "";
|
||||||
|
|
||||||
if (!data["aprs_is"].containsKey("active") ||
|
if (!data["aprs_is"].containsKey("active") ||
|
||||||
!data["aprs_is"].containsKey("passcode") ||
|
!data["aprs_is"].containsKey("passcode") ||
|
||||||
@@ -431,6 +450,7 @@ void Configuration::setDefaultValues() {
|
|||||||
wifiAutoAP.timeout = 10;
|
wifiAutoAP.timeout = 10;
|
||||||
|
|
||||||
callsign = "N0CALL-10";
|
callsign = "N0CALL-10";
|
||||||
|
tacticalCallsign = "";
|
||||||
|
|
||||||
aprs_is.active = false;
|
aprs_is.active = false;
|
||||||
aprs_is.passcode = "XYZVW";
|
aprs_is.passcode = "XYZVW";
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace DIGI_Utils {
|
|||||||
String tempPath = path;
|
String tempPath = path;
|
||||||
|
|
||||||
if (path.indexOf("WIDE1-1") != -1 && (Config.digi.mode == 2 || Config.digi.mode == 3)) {
|
if (path.indexOf("WIDE1-1") != -1 && (Config.digi.mode == 2 || Config.digi.mode == 3)) {
|
||||||
tempPath.replace("WIDE1-1", Config.callsign + "*");
|
tempPath.replace("WIDE1-1", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*");
|
||||||
} else if (path.indexOf("WIDE2-") != -1 && Config.digi.mode == 3) {
|
} else if (path.indexOf("WIDE2-") != -1 && Config.digi.mode == 3) {
|
||||||
if (path.indexOf(",WIDE1*") != -1) {
|
if (path.indexOf(",WIDE1*") != -1) {
|
||||||
tempPath.remove(path.indexOf(",WIDE1*"), 7);
|
tempPath.remove(path.indexOf(",WIDE1*"), 7);
|
||||||
@@ -58,9 +58,9 @@ namespace DIGI_Utils {
|
|||||||
tempPath.remove(path.indexOf("*"), 1);
|
tempPath.remove(path.indexOf("*"), 1);
|
||||||
}
|
}
|
||||||
if (path.indexOf("WIDE2-1") != -1) {
|
if (path.indexOf("WIDE2-1") != -1) {
|
||||||
tempPath.replace("WIDE2-1", Config.callsign + "*");
|
tempPath.replace("WIDE2-1", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*");
|
||||||
} else if (path.indexOf("WIDE2-2") != -1) {
|
} else if (path.indexOf("WIDE2-2") != -1) {
|
||||||
tempPath.replace("WIDE2-2", Config.callsign + "*,WIDE2-1");
|
tempPath.replace("WIDE2-2", (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign) + "*,WIDE2-1");
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ namespace DIGI_Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
packetToRepeat += ",";
|
packetToRepeat += ",";
|
||||||
packetToRepeat += Config.callsign;
|
packetToRepeat += (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||||
packetToRepeat += "*";
|
packetToRepeat += "*";
|
||||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(suffix)));
|
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(suffix)));
|
||||||
return packetToRepeat;
|
return packetToRepeat;
|
||||||
@@ -147,8 +147,8 @@ namespace DIGI_Utils {
|
|||||||
temp = packet.substring(3);
|
temp = packet.substring(3);
|
||||||
Sender = packet.substring(3, packet.indexOf(">"));
|
Sender = packet.substring(3, packet.indexOf(">"));
|
||||||
}
|
}
|
||||||
if (Sender != Config.callsign) { // Avoid listening to own packets
|
if (Sender != (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign)) { // Avoid listening to own packets
|
||||||
if (!thirdPartyPacket && !Utils::checkValidCallsign(Sender)) {
|
if (!thirdPartyPacket && Config.tacticalCallsign == "" && !Utils::checkValidCallsign(Sender)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) {
|
if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) {
|
||||||
@@ -159,7 +159,7 @@ namespace DIGI_Utils {
|
|||||||
String AddresseeAndMessage = temp.substring(temp.indexOf("::") + 2);
|
String AddresseeAndMessage = temp.substring(temp.indexOf("::") + 2);
|
||||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||||
Addressee.trim();
|
Addressee.trim();
|
||||||
if (Addressee == Config.callsign) { // it's a message for me!
|
if (Addressee == (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign)) { // it's a message for me!
|
||||||
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
|
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern HardwareSerial gpsSerial;
|
extern HardwareSerial gpsSerial;
|
||||||
extern TinyGPSPlus gps;
|
extern TinyGPSPlus gps;
|
||||||
|
extern bool callsignIsValid;
|
||||||
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
||||||
|
|
||||||
|
|
||||||
@@ -44,20 +45,31 @@ namespace GPS_Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void generateBeacons() {
|
void generateBeacons() {
|
||||||
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
|
String beaconPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
|
||||||
displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000);
|
String encodedGPS = APRSPacketLib::encodeGPSIntoBase91(Config.beacon.latitude, Config.beacon.longitude, 0, 0, Config.beacon.symbol, false, 0, true, Config.beacon.ambiguityLevel);
|
||||||
Config.loramodule.txActive = false;
|
|
||||||
Config.aprs_is.messagesToRF = false;
|
if (Config.callsign.indexOf("NOCALL-10") != 0) {
|
||||||
Config.aprs_is.objectsToRF = false;
|
if (!callsignIsValid) {
|
||||||
|
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;
|
||||||
|
} else if (callsignIsValid && Config.tacticalCallsign != "") {
|
||||||
|
beaconPacket = APRSPacketLib::generateBasePacket(Config.tacticalCallsign, "APLRG1", Config.beacon.path);
|
||||||
|
Config.aprs_is.active = false;
|
||||||
|
Config.beacon.sendViaAPRSIS = false;
|
||||||
|
Config.backupDigiMode = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Config.beacon.sendViaAPRSIS = false;
|
||||||
Config.beacon.sendViaRF = false;
|
Config.beacon.sendViaRF = false;
|
||||||
Config.digi.mode = 0;
|
|
||||||
Config.backupDigiMode = false;
|
|
||||||
}
|
}
|
||||||
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, false, 0, true, Config.beacon.ambiguityLevel);
|
|
||||||
|
|
||||||
iGateBeaconPacket = beaconPacket;
|
iGateBeaconPacket = beaconPacket;
|
||||||
iGateBeaconPacket += ",qAC:!";
|
iGateBeaconPacket += ",qAC:=";
|
||||||
iGateBeaconPacket += Config.beacon.overlay;
|
iGateBeaconPacket += Config.beacon.overlay;
|
||||||
iGateBeaconPacket += encodedGPS;
|
iGateBeaconPacket += encodedGPS;
|
||||||
|
|
||||||
@@ -132,7 +144,7 @@ namespace GPS_Utils {
|
|||||||
convertedLongitude += Longitude.substring(3,5).toFloat() / 60; // Next 2 digits (Minutes)
|
convertedLongitude += Longitude.substring(3,5).toFloat() / 60; // Next 2 digits (Minutes)
|
||||||
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
|
||||||
|
|
||||||
return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));
|
return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +154,7 @@ namespace GPS_Utils {
|
|||||||
|
|
||||||
const uint8_t nonEncondedLatitudeOffset = 9; // "N" / "S"
|
const uint8_t nonEncondedLatitudeOffset = 9; // "N" / "S"
|
||||||
const uint8_t nonEncondedLongitudeOffset = 19; // "E" / "W"
|
const uint8_t nonEncondedLongitudeOffset = 19; // "E" / "W"
|
||||||
const uint8_t encondedByteOffset = 14;
|
const uint8_t encodedByteOffset = 14;
|
||||||
|
|
||||||
int indexOfExclamation = packet.indexOf(":!");
|
int indexOfExclamation = packet.indexOf(":!");
|
||||||
int indexOfEqual = packet.indexOf(":=");
|
int indexOfEqual = packet.indexOf(":=");
|
||||||
@@ -156,18 +168,18 @@ namespace GPS_Utils {
|
|||||||
|
|
||||||
int latitudeIndex = baseIndex + nonEncondedLatitudeOffset;
|
int latitudeIndex = baseIndex + nonEncondedLatitudeOffset;
|
||||||
int longitudeIndex = baseIndex + nonEncondedLongitudeOffset;
|
int longitudeIndex = baseIndex + nonEncondedLongitudeOffset;
|
||||||
int encondedByteIndex = baseIndex + encondedByteOffset;
|
int encodedByteIndex = baseIndex + encodedByteOffset;
|
||||||
int packetLength = packet.length();
|
int packetLength = packet.length();
|
||||||
|
|
||||||
if (latitudeIndex >= packetLength || longitudeIndex >= packetLength || encondedByteIndex >= packetLength) return " _ / _ / _ ";
|
if (latitudeIndex < packetLength && longitudeIndex < packetLength) {
|
||||||
|
char latChar = packet[latitudeIndex];
|
||||||
char latChar = packet[latitudeIndex];
|
char lngChar = packet[longitudeIndex];
|
||||||
char lngChar = packet[longitudeIndex];
|
if ((latChar == 'N' || latChar == 'S') && (lngChar == 'E' || lngChar == 'W')) return getReceivedGPS(packet);
|
||||||
if ((latChar == 'N' || latChar == 'S') && (lngChar == 'E' || lngChar == 'W')) return getReceivedGPS(packet);
|
}
|
||||||
|
if (encodedByteIndex < packetLength) {
|
||||||
char byteChar = packet[encondedByteIndex];
|
char byteChar = packet[encodedByteIndex];
|
||||||
if (byteChar == 'G' || byteChar == 'Q' || byteChar == '[' || byteChar == 'H' || byteChar == 'X' || byteChar == '3') return decodeEncodedGPS(packet);
|
if (byteChar == 'G' || byteChar == 'Q' || byteChar == '[' || byteChar == 'H' || byteChar == 'X' || byteChar == '3') return decodeEncodedGPS(packet);
|
||||||
|
}
|
||||||
return " _ / _ / _ ";
|
return " _ / _ / _ ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace LoRa_Utils {
|
|||||||
|
|
||||||
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
||||||
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
||||||
float signalBandwidth = Config.loramodule.rxSignalBandwidth/1000;
|
float signalBandwidth = Config.loramodule.rxSignalBandwidth / 1000;
|
||||||
radio.setBandwidth(signalBandwidth);
|
radio.setBandwidth(signalBandwidth);
|
||||||
radio.setCRC(true);
|
radio.setCRC(true);
|
||||||
|
|
||||||
@@ -151,20 +151,20 @@ namespace LoRa_Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void changeFreqTx() {
|
void changeFreqTx() {
|
||||||
delay(300);
|
|
||||||
float freq = (float)Config.loramodule.txFreq / 1000000;
|
float freq = (float)Config.loramodule.txFreq / 1000000;
|
||||||
radio.setFrequency(freq);
|
radio.setFrequency(freq);
|
||||||
radio.setSpreadingFactor(Config.loramodule.txSpreadingFactor);
|
radio.setSpreadingFactor(Config.loramodule.txSpreadingFactor);
|
||||||
radio.setCodingRate(Config.loramodule.txCodingRate4);
|
radio.setCodingRate(Config.loramodule.txCodingRate4);
|
||||||
|
float signalBandwidth = Config.loramodule.txSignalBandwidth / 1000;
|
||||||
radio.setBandwidth(Config.loramodule.txSignalBandwidth);
|
radio.setBandwidth(Config.loramodule.txSignalBandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeFreqRx() {
|
void changeFreqRx() {
|
||||||
delay(300);
|
|
||||||
float freq = (float)Config.loramodule.rxFreq / 1000000;
|
float freq = (float)Config.loramodule.rxFreq / 1000000;
|
||||||
radio.setFrequency(freq);
|
radio.setFrequency(freq);
|
||||||
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
||||||
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
||||||
|
float signalBandwidth = Config.loramodule.rxSignalBandwidth / 1000;
|
||||||
radio.setBandwidth(Config.loramodule.rxSignalBandwidth);
|
radio.setBandwidth(Config.loramodule.rxSignalBandwidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "battery_utils.h"
|
#include "battery_utils.h"
|
||||||
#include "board_pinout.h"
|
#include "board_pinout.h"
|
||||||
#include "power_utils.h"
|
#include "power_utils.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
|
extern bool callsignIsValid;
|
||||||
|
|
||||||
|
|
||||||
namespace POWER_Utils {
|
namespace POWER_Utils {
|
||||||
@@ -326,6 +328,7 @@ namespace POWER_Utils {
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
BATTERY_Utils::setup();
|
BATTERY_Utils::setup();
|
||||||
BATTERY_Utils::startupBatteryHealth();
|
BATTERY_Utils::startupBatteryHealth();
|
||||||
|
callsignIsValid = Utils::checkValidCallsign(Config.callsign);
|
||||||
setCpuFrequencyMhz(80);
|
setCpuFrequencyMhz(80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace QUERY_Utils {
|
|||||||
String queryQuestion = query;
|
String queryQuestion = query;
|
||||||
queryQuestion.toUpperCase();
|
queryQuestion.toUpperCase();
|
||||||
if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") {
|
if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") {
|
||||||
answer.concat("?APRSV ?APRSP ?APRSL ?APRSSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign
|
answer.concat("?APRSV ?APRSP ?APRSL ?APRSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign
|
||||||
} else if (queryQuestion == "?APRSV") {
|
} else if (queryQuestion == "?APRSV") {
|
||||||
answer.concat("CA2RXU_LoRa_iGate v");
|
answer.concat("CA2RXU_LoRa_iGate v");
|
||||||
answer.concat(versionNumber);
|
answer.concat(versionNumber);
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ bool sendStartTelemetry = true;
|
|||||||
bool beaconUpdate = false;
|
bool beaconUpdate = false;
|
||||||
uint32_t lastBeaconTx = 0;
|
uint32_t lastBeaconTx = 0;
|
||||||
uint32_t lastScreenOn = millis();
|
uint32_t lastScreenOn = millis();
|
||||||
|
bool callsignIsValid = false;
|
||||||
String beaconPacket;
|
String beaconPacket;
|
||||||
String secondaryBeaconPacket;
|
String secondaryBeaconPacket;
|
||||||
|
|
||||||
@@ -120,7 +121,11 @@ namespace Utils {
|
|||||||
#ifdef INTERNAL_LED_PIN
|
#ifdef INTERNAL_LED_PIN
|
||||||
digitalWrite(INTERNAL_LED_PIN,LOW);
|
digitalWrite(INTERNAL_LED_PIN,LOW);
|
||||||
#endif
|
#endif
|
||||||
firstLine = Config.callsign;
|
if (Config.tacticalCallsign != "") {
|
||||||
|
firstLine = Config.tacticalCallsign;
|
||||||
|
} else {
|
||||||
|
firstLine = Config.callsign;
|
||||||
|
}
|
||||||
seventhLine = " listening...";
|
seventhLine = " listening...";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +192,12 @@ namespace Utils {
|
|||||||
}
|
}
|
||||||
beaconPacket += Config.beacon.comment;
|
beaconPacket += Config.beacon.comment;
|
||||||
secondaryBeaconPacket += Config.beacon.comment;
|
secondaryBeaconPacket += Config.beacon.comment;
|
||||||
|
if (callsignIsValid && Config.tacticalCallsign != "") {
|
||||||
|
beaconPacket += " de ";
|
||||||
|
beaconPacket += Config.callsign;
|
||||||
|
secondaryBeaconPacket += " de ";
|
||||||
|
secondaryBeaconPacket += Config.callsign;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(BATTERY_PIN) || defined(HAS_AXP192) || defined(HAS_AXP2101)
|
#if defined(BATTERY_PIN) || defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
if (Config.battery.sendInternalVoltage || Config.battery.monitorInternalVoltage) {
|
if (Config.battery.sendInternalVoltage || Config.battery.monitorInternalVoltage) {
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ namespace WEB_Utils {
|
|||||||
Config.startupDelay = getParamIntSafe("startupDelay", Config.startupDelay);
|
Config.startupDelay = getParamIntSafe("startupDelay", Config.startupDelay);
|
||||||
|
|
||||||
Config.callsign = getParamStringSafe("callsign", Config.callsign);
|
Config.callsign = getParamStringSafe("callsign", Config.callsign);
|
||||||
|
Config.tacticalCallsign = getParamStringSafe("tacticalCallsign", Config.tacticalCallsign);
|
||||||
|
|
||||||
Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password);
|
Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password);
|
||||||
Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout);
|
Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace WIFI_Utils {
|
|||||||
delay(500);
|
delay(500);
|
||||||
unsigned long start = millis();
|
unsigned long start = millis();
|
||||||
displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0);
|
displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0);
|
||||||
Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.println("' ...");
|
Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.print("' ");
|
||||||
WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str());
|
WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str());
|
||||||
while (WiFi.status() != WL_CONNECTED && wifiCounter<myWiFiAPSize) {
|
while (WiFi.status() != WL_CONNECTED && wifiCounter<myWiFiAPSize) {
|
||||||
delay(500);
|
delay(500);
|
||||||
|
|||||||
75
variants/heltec_wifi_lora_32_V4/board_pinout.h
Normal file
75
variants/heltec_wifi_lora_32_V4/board_pinout.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOARD_PINOUT_H_
|
||||||
|
#define BOARD_PINOUT_H_
|
||||||
|
|
||||||
|
// LoRa Radio
|
||||||
|
#define HAS_SX1262
|
||||||
|
#define HAS_TCXO
|
||||||
|
#define RADIO_SCLK_PIN 9
|
||||||
|
#define RADIO_MISO_PIN 11
|
||||||
|
#define RADIO_MOSI_PIN 10
|
||||||
|
#define RADIO_CS_PIN 8
|
||||||
|
#define RADIO_RST_PIN 12
|
||||||
|
#define RADIO_DIO1_PIN 14
|
||||||
|
#define RADIO_BUSY_PIN 13
|
||||||
|
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
|
||||||
|
#define GPIO_WAKEUP_PIN GPIO_SEL_14
|
||||||
|
|
||||||
|
// I2C
|
||||||
|
#define USE_WIRE_WITH_OLED_PINS
|
||||||
|
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||||
|
#define BOARD_I2C_SDA 41
|
||||||
|
#define BOARD_I2C_SCL 42
|
||||||
|
|
||||||
|
// Display
|
||||||
|
#define HAS_DISPLAY
|
||||||
|
|
||||||
|
#undef OLED_SDA
|
||||||
|
#undef OLED_SCL
|
||||||
|
#undef OLED_RST
|
||||||
|
|
||||||
|
#define OLED_SDA 17
|
||||||
|
#define OLED_SCL 18
|
||||||
|
#define OLED_RST 21
|
||||||
|
#define OLED_DISPLAY_HAS_RST_PIN
|
||||||
|
|
||||||
|
// Aditional Config
|
||||||
|
#define INTERNAL_LED_PIN 35
|
||||||
|
#define BATTERY_PIN 1
|
||||||
|
#define VEXT_CTRL 36
|
||||||
|
#define ADC_CTRL 37
|
||||||
|
|
||||||
|
// GPS ??
|
||||||
|
#define VGNS_CTRL 34 // cambiar nombre para prender GPS ?
|
||||||
|
// wakeup 40
|
||||||
|
// TX 39
|
||||||
|
// RX 38
|
||||||
|
// RST 42
|
||||||
|
// PPS 41
|
||||||
|
//#define GPS_L76K
|
||||||
|
|
||||||
|
// // active low, powers the oled display and the lora antenna boost
|
||||||
|
|
||||||
|
//#define LORA_PA_POWER 7 // power en
|
||||||
|
//#define LORA_PA_EN 2
|
||||||
|
//#define LORA_PA_TX_EN 46 // enable tx
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
12
variants/heltec_wifi_lora_32_V4/platformio.ini
Normal file
12
variants/heltec_wifi_lora_32_V4/platformio.ini
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[env:heltec_wifi_lora_32_V4]
|
||||||
|
board = heltec_wifi_lora_32_V3
|
||||||
|
board_build.mcu = esp32s3
|
||||||
|
build_flags =
|
||||||
|
${common.build_flags}
|
||||||
|
-D RADIOLIB_EXCLUDE_LR11X0=1
|
||||||
|
-D RADIOLIB_EXCLUDE_SX127X=1
|
||||||
|
-D RADIOLIB_EXCLUDE_SX128X=1
|
||||||
|
-D HELTEC_V4
|
||||||
|
lib_deps =
|
||||||
|
${common.lib_deps}
|
||||||
|
${common.display_libs}
|
||||||
Reference in New Issue
Block a user