mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-10-31 02:51:58 +01:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3618558b21 | ||
|
|
e1eda2e64a | ||
|
|
759cddd0e5 | ||
|
|
8186ff4fbd | ||
|
|
3720fe9881 | ||
|
|
5d04c56fd2 | ||
|
|
ee65f953d6 | ||
|
|
c952ea0159 | ||
|
|
21a42ef157 | ||
|
|
53ee07a7c1 | ||
|
|
12a0f5bed1 | ||
|
|
08bfb013ce |
No files matched your search
Vendored
+2
-1
@@ -5,6 +5,7 @@
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
"ms-vscode.cpptools-extension-pack",
|
||||
"pioarduino.pioarduino-ide"
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -38,7 +38,7 @@ lib_deps =
|
||||
ESP32Async/AsyncTCP @ 3.4.10
|
||||
ESP32Async/ESPAsyncWebServer @ 3.11.1
|
||||
mikalhart/TinyGPSPlus @ 1.0.3
|
||||
richonguzman/APRSPacketLib @ 1.0.4
|
||||
richonguzman/APRSPacketLib @ 1.0.6
|
||||
display_libs =
|
||||
adafruit/Adafruit GFX Library @ 1.12.6
|
||||
adafruit/Adafruit SSD1306 @ 2.5.17
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 105 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 93 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
+19
-2
@@ -1520,7 +1520,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
<label
|
||||
for="tnc.enableSerial"
|
||||
class="form-label"
|
||||
>Enable Serial KISS</label
|
||||
>Enable Serial</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1552,7 +1552,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
<label
|
||||
for="tnc.acceptOwn"
|
||||
class="form-label"
|
||||
>Accept own frames via KISS</label
|
||||
>Accept own frames</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1572,6 +1572,23 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-6">
|
||||
<label
|
||||
for="tnc.kissProtocol"
|
||||
class="form-label"
|
||||
>Protocol</label
|
||||
>
|
||||
<select
|
||||
class="form-select form-select"
|
||||
name="tnc.kissProtocol"
|
||||
id="tnc.kissProtocol"
|
||||
>
|
||||
<option value="KISS" selected>KISS</option>
|
||||
<option value="TNC2">TNC2</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
+20
-12
@@ -226,6 +226,7 @@ function loadSettings(settings) {
|
||||
document.getElementById("tnc.enableSerial").checked = settings.tnc.enableSerial;
|
||||
document.getElementById("tnc.acceptOwn").checked = settings.tnc.acceptOwn;
|
||||
document.getElementById("tnc.aprsBridgeActive").checked = settings.tnc.aprsBridgeActive;
|
||||
document.getElementById("tnc.kissProtocol").value = settings.tnc.kissProtocol ? "KISS" : "TNC2";
|
||||
}
|
||||
|
||||
// MQTT
|
||||
@@ -668,9 +669,9 @@ function setMapMessage(text) {
|
||||
* "L&" Alternate table with overlay
|
||||
*
|
||||
* Sprite layout:
|
||||
* aprs-symbols-48-0.png = Primary table
|
||||
* aprs-symbols-48-1.png = Alternate table
|
||||
* aprs-symbols-48-2.png = Overlay characters
|
||||
* aprs-symbols-24-0.png = Primary table
|
||||
* aprs-symbols-24-1.png = Alternate table
|
||||
* aprs-symbols-24-2.png = Overlay characters
|
||||
*/
|
||||
|
||||
function getAprsSymbolIcon(symbol, callsign = "") {
|
||||
@@ -717,8 +718,7 @@ function getAprsSymbolIcon(symbol, callsign = "") {
|
||||
|
||||
/*
|
||||
* Sprite sheet contains 16 columns x 6 rows.
|
||||
* Each cell occupies 24x24 CSS px, but the underlying PNG assets are
|
||||
* actually 48x48 px/cell (2x) for sharpness on high-DPI screens; the
|
||||
* Each cell occupies 24x24 CSS px; the
|
||||
* "background-size" below tells the browser to scale the sheet back
|
||||
* down to its original 24px-per-cell layout, so all position math
|
||||
* stays in 24px units regardless of source resolution.
|
||||
@@ -731,8 +731,8 @@ function getAprsSymbolIcon(symbol, callsign = "") {
|
||||
|
||||
const sprite =
|
||||
table === "/"
|
||||
? "/aprs-symbols-48-0.png"
|
||||
: "/aprs-symbols-48-1.png";
|
||||
? "/aprs-symbols-24-0.png"
|
||||
: "/aprs-symbols-24-1.png";
|
||||
|
||||
const x = -(col * 24);
|
||||
const y = -(row * 24);
|
||||
@@ -792,7 +792,7 @@ function getAprsSymbolIcon(symbol, callsign = "") {
|
||||
top:0;
|
||||
width:24px;
|
||||
height:24px;
|
||||
background-image:url('/aprs-symbols-48-2.png');
|
||||
background-image:url('/aprs-symbols-24-2.png');
|
||||
background-repeat:no-repeat;
|
||||
background-position:${ox}px ${oy}px;
|
||||
background-size:${sheetSize};
|
||||
@@ -865,11 +865,17 @@ function getUsedDigipeaters(path) {
|
||||
function describeMapPath(station) {
|
||||
const digis = getUsedDigipeaters(station.path);
|
||||
|
||||
if (!digis.length) {
|
||||
return "Direct";
|
||||
// heardDirect viene del firmware: true si ALGUNA VEZ se oyo directo,
|
||||
// aunque el ultimo paquete haya llegado repetido.
|
||||
if (station.heardDirect && digis.length) {
|
||||
return "Direct+Via: " + digis.join(" → ");
|
||||
}
|
||||
|
||||
return "Via: " + digis.join(" → ");
|
||||
if (digis.length) {
|
||||
return "Via: " + digis.join(" → ");
|
||||
}
|
||||
|
||||
return "Direct";
|
||||
}
|
||||
|
||||
|
||||
@@ -904,8 +910,10 @@ function drawStationRoute(station) {
|
||||
|
||||
points.push(iGateLatLng);
|
||||
|
||||
const routeColor = digis.length > 0 ? "#2e7d32" : "#1565c0";
|
||||
|
||||
mapRouteLayer = L.polyline(points, {
|
||||
color: "#e53935",
|
||||
color: routeColor,
|
||||
weight: 3,
|
||||
opacity: 0.9
|
||||
}).addTo(mapInstance);
|
||||
|
||||
@@ -28,10 +28,9 @@ namespace APRS_IS_Utils {
|
||||
void connect();
|
||||
|
||||
void checkStatus();
|
||||
String checkForStartingBytes(const String& packet);
|
||||
|
||||
String buildPacketToUpload(const String& packet);
|
||||
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty);
|
||||
bool processReceivedLoRaMessage(const String& sender, const String& packet);
|
||||
void processLoRaPacket(const String& packet);
|
||||
|
||||
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType);
|
||||
|
||||
@@ -132,6 +132,7 @@ public:
|
||||
bool enableSerial;
|
||||
bool acceptOwn;
|
||||
bool aprsBridgeActive;
|
||||
bool kissProtocol; // true = KISS, false = TNC2 -- applies to both Serial and TCP server
|
||||
};
|
||||
|
||||
class OTA {
|
||||
|
||||
@@ -24,10 +24,9 @@
|
||||
|
||||
namespace DIGI_Utils {
|
||||
|
||||
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq);
|
||||
String generateDigipeatedPacket(const String& packet, bool thirdParty);
|
||||
String buildPacket(const String& path, const String& packet, bool crossFreq);
|
||||
String generateDigipeatedPacket(const String& packet);
|
||||
void processLoRaPacket(const String& packet);
|
||||
void checkEcoMode();
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -25,13 +25,8 @@
|
||||
namespace GPS_Utils {
|
||||
|
||||
String getiGateLoRaBeaconPacket();
|
||||
char *ax25_base91enc(char *s, uint8_t n, uint32_t v);
|
||||
String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol);
|
||||
void generateBeaconFirstPart();
|
||||
void generateBeacons();
|
||||
String decodeEncodedGPS(const String& packet);
|
||||
String getReceivedGPS(const String& packet);
|
||||
String getDistanceAndComment(const String& packet);
|
||||
String buildDistanceAndComment(float latitude, float longitude, const String& comment);
|
||||
|
||||
void setup();
|
||||
void getData();
|
||||
|
||||
@@ -34,6 +34,7 @@ struct MapStation {
|
||||
char lastHeard[10]; // "HH:MM:SS" si hay NTP valido, "" si no
|
||||
char path[96]; // last path received
|
||||
uint32_t lastHeardMillis; // millis() -> ordenar / expirar (no se muestra)
|
||||
bool heardDirect; // true si ALGUNA VEZ se oyo sin digipeaters (no se resetea)
|
||||
};
|
||||
|
||||
namespace MAP_Utils {
|
||||
|
||||
@@ -84,7 +84,6 @@ public:
|
||||
// Ethernet methods
|
||||
bool ethernetConnect(eth_phy_type_t type, uint8_t phy_addr, uint8_t mdc, uint8_t mdio, int power, eth_clock_mode_t clock_mode, bool use_mac_from_efuse = false);
|
||||
bool setEthernetIP(const String& staticIP, const String& gateway, const String& subnet, const String& dns1, const String& dns2);
|
||||
bool ethernetDisconnect();
|
||||
IPAddress getEthernetIP() const;
|
||||
String getEthernetMACAddress() const;
|
||||
|
||||
|
||||
@@ -19,12 +19,16 @@
|
||||
#ifndef SYSLOG_H_
|
||||
#define SYSLOG_H_
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
namespace SYSLOG_Utils {
|
||||
|
||||
void log(const uint8_t type ,const String& packet, const int rssi, const float snr, const int freqError);
|
||||
void logLoRaRx(APRSPacket& aprsPacket, const String& packet, const int rssi, const float snr, const int freqError);
|
||||
void logAPRSISTx(const String& packet);
|
||||
void logLoRaTx(const String& packet);
|
||||
void logCRCError(const String& packet, const int rssi, const float snr, const int freqError);
|
||||
void setup();
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -19,9 +19,9 @@
|
||||
#ifndef UTILS_H_
|
||||
#define UTILS_H_
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
class ReceivedPacket {
|
||||
public:
|
||||
String rxTime;
|
||||
@@ -39,7 +39,8 @@ namespace Utils {
|
||||
void checkBeaconInterval();
|
||||
void checkDisplayInterval();
|
||||
void validateFreqs();
|
||||
void typeOfPacket(const String& packet, const uint8_t packetType);
|
||||
void updateLoRaPacketDisplayInfo(APRSPacket& aprsPacket, const uint8_t packetType);
|
||||
void updateAPRSISPacketDisplayInfo(const String& packet);
|
||||
void print(const String& text);
|
||||
void println(const String& text);
|
||||
void checkRebootMode();
|
||||
|
||||
+3
-3
@@ -29,9 +29,9 @@ board_build.embed_files =
|
||||
data_embed/leaflet.css.gz
|
||||
data_embed/leaflet.js.gz
|
||||
data_embed/favicon.png.gz
|
||||
data_embed/aprs-symbols-48-0.png.gz
|
||||
data_embed/aprs-symbols-48-1.png.gz
|
||||
data_embed/aprs-symbols-48-2.png.gz
|
||||
data_embed/aprs-symbols-24-0.png.gz
|
||||
data_embed/aprs-symbols-24-1.png.gz
|
||||
data_embed/aprs-symbols-24-2.png.gz
|
||||
extra_scripts =
|
||||
pre:tools/compress.py
|
||||
debug_tool = esp-prog
|
||||
@@ -68,7 +68,7 @@ ___________________________________________________________________*/
|
||||
#endif
|
||||
|
||||
|
||||
String versionDate = "2026-08-25";
|
||||
String versionDate = "2026-09-23";
|
||||
String versionNumber = "4.0.1";
|
||||
Configuration Config;
|
||||
WiFiClient aprsIsClient;
|
||||
|
||||
+23
-34
@@ -33,6 +33,7 @@
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern APRSPacket lastAprsPacket;
|
||||
extern NetworkManager *networkManager;
|
||||
extern WiFiClient aprsIsClient;
|
||||
extern uint32_t lastScreenOn;
|
||||
@@ -135,11 +136,6 @@ namespace APRS_IS_Utils {
|
||||
secondLine += aprsisState;
|
||||
}
|
||||
|
||||
String checkForStartingBytes(const String& packet) {
|
||||
int index = packet.indexOf("\x3c\xff\x01");
|
||||
return (index != -1) ? packet.substring(0, index) : packet;
|
||||
}
|
||||
|
||||
String buildPacketToUpload(const String& packet) {
|
||||
int colonIndex = packet.indexOf(":");
|
||||
String packetToUpload = packet.substring(3, colonIndex);
|
||||
@@ -149,11 +145,11 @@ namespace APRS_IS_Utils {
|
||||
packetToUpload += ",qAO,";
|
||||
}
|
||||
packetToUpload += Config.callsign;
|
||||
packetToUpload += checkForStartingBytes(packet.substring(colonIndex));
|
||||
packetToUpload += APRSPacketLib::checkForStartingBytes(packet.substring(colonIndex));
|
||||
return packetToUpload;
|
||||
}
|
||||
|
||||
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty) {
|
||||
bool processReceivedLoRaMessage(const String& sender, const String& packet) {
|
||||
String receivedMessage;
|
||||
int leftCurlyBraceIndex = packet.indexOf("{");
|
||||
int colonIndex = packet.indexOf(":");
|
||||
@@ -165,7 +161,7 @@ namespace APRS_IS_Utils {
|
||||
|
||||
String addToBuffer = Config.callsign;
|
||||
addToBuffer += ">APLRG1";
|
||||
if (!thirdParty) addToBuffer += ",RFONLY";
|
||||
if (lastAprsPacket.header == "") addToBuffer += ",RFONLY";
|
||||
if (Config.beacon.path != "") {
|
||||
addToBuffer += ",";
|
||||
addToBuffer += Config.beacon.path;
|
||||
@@ -186,51 +182,44 @@ namespace APRS_IS_Utils {
|
||||
receivedMessage = packet.substring(colonIndex + 1);
|
||||
}
|
||||
if (receivedMessage.indexOf("?") == 0) {
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
}
|
||||
STATION_Utils::addToOutputPacketBuffer(QUERY_Utils::process(receivedMessage, sender, false, thirdParty));
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) displayToggle(true);
|
||||
|
||||
STATION_Utils::addToOutputPacketBuffer(QUERY_Utils::process(receivedMessage, sender, false, lastAprsPacket.header != ""));
|
||||
lastScreenOn = millis();
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, "Callsign = " + sender, "TYPE --> QUERY", 0);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void processLoRaPacket(const String& packet) {
|
||||
if (passcodeValid && (aprsIsClient.connected() || modemLoggedToAPRSIS)) {
|
||||
if (packet.indexOf("NOGATE") == -1 && packet.indexOf("RFONLY") == -1) {
|
||||
int firstColonIndex = packet.indexOf(":");
|
||||
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] != '}' && packet.indexOf("TCPIP") == -1) {
|
||||
const String& Sender = packet.substring(3, packet.indexOf(">"));
|
||||
if (Sender != Config.callsign && Utils::callsignIsValid(Sender)) {
|
||||
STATION_Utils::updateLastHeard(Sender);
|
||||
Utils::typeOfPacket(packet.substring(3), 0); // LoRa-APRS
|
||||
int doubleColonIndex = packet.indexOf("::");
|
||||
const String& AddresseeAndMessage = packet.substring(doubleColonIndex + 2);
|
||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||
Addressee.trim();
|
||||
if (lastAprsPacket.path.indexOf("NOGATE") == -1 && lastAprsPacket.path.indexOf("RFONLY") == -1) {
|
||||
if (lastAprsPacket.header == "" && lastAprsPacket.path.indexOf("TCPIP") == -1) {
|
||||
if (lastAprsPacket.sender != Config.callsign && Utils::callsignIsValid(lastAprsPacket.sender)) {
|
||||
STATION_Utils::updateLastHeard(lastAprsPacket.sender);
|
||||
Utils::updateLoRaPacketDisplayInfo(lastAprsPacket, 0); // LoRa-APRS
|
||||
bool queryMessage = false;
|
||||
if (doubleColonIndex > 10 && Addressee == Config.callsign) { // its a message for me!
|
||||
queryMessage = processReceivedLoRaMessage(Sender, checkForStartingBytes(AddresseeAndMessage), false);
|
||||
if (lastAprsPacket.type == 1 && lastAprsPacket.addressee == Config.callsign) { // its a message for me!
|
||||
String AddresseeAndMessage = lastAprsPacket.addressee + ":" + lastAprsPacket.payload;
|
||||
queryMessage = processReceivedLoRaMessage(lastAprsPacket.sender, APRSPacketLib::checkForStartingBytes(AddresseeAndMessage));
|
||||
}
|
||||
if (queryMessage) return;
|
||||
|
||||
const String& aprsPacket = buildPacketToUpload(packet);
|
||||
const String& aprsPacketToUpload = buildPacketToUpload(packet);
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
}
|
||||
lastScreenOn = millis();
|
||||
#ifdef HAS_A7670
|
||||
stationBeacon = true;
|
||||
A7670_Utils::uploadToAPRSIS(aprsPacket);
|
||||
A7670_Utils::uploadToAPRSIS(aprsPacketToUpload);
|
||||
stationBeacon = false;
|
||||
#else
|
||||
upload(aprsPacket);
|
||||
upload(aprsPacketToUpload);
|
||||
#endif
|
||||
Utils::println("---> Uploaded to APRS-IS");
|
||||
Utils::println("(Uploaded to APRS-IS)");
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
}
|
||||
}
|
||||
@@ -351,7 +340,7 @@ namespace APRS_IS_Utils {
|
||||
#else
|
||||
upload(queryAnswer);
|
||||
#endif
|
||||
SYSLOG_Utils::log(2, queryAnswer, 0, 0.0, 0); // APRSIS TX
|
||||
SYSLOG_Utils::logAPRSISTx(queryAnswer);
|
||||
fifthLine = "APRS-IS ----> APRS-IS";
|
||||
sixthLine = Config.callsign;
|
||||
for (int j = sixthLine.length();j < 9;j++) {
|
||||
@@ -369,7 +358,7 @@ namespace APRS_IS_Utils {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 1));
|
||||
displayToggle(true);
|
||||
lastScreenOn = currentTime;
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
Utils::updateAPRSISPacketDisplayInfo(packet); // APRS-LoRa
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
}
|
||||
}
|
||||
@@ -379,7 +368,7 @@ namespace APRS_IS_Utils {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 5));
|
||||
displayToggle(true);
|
||||
lastScreenOn = currentTime;
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
Utils::updateAPRSISPacketDisplayInfo(packet); // APRS-LoRa
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.println(" ---> Rejected (Time): No Tx");
|
||||
|
||||
@@ -157,6 +157,7 @@ bool Configuration::writeFile() {
|
||||
data["tnc"]["enableSerial"] = tnc.enableSerial;
|
||||
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
|
||||
data["tnc"]["aprsBridgeActive"] = tnc.aprsBridgeActive;
|
||||
data["tnc"]["kissProtocol"] = tnc.kissProtocol;
|
||||
|
||||
data["mqtt"]["active"] = mqtt.active;
|
||||
data["mqtt"]["server"] = mqtt.server;
|
||||
@@ -369,11 +370,13 @@ bool Configuration::readFile() {
|
||||
if (data["tnc"]["enableServer"].isNull() ||
|
||||
data["tnc"]["enableSerial"].isNull() ||
|
||||
data["tnc"]["acceptOwn"].isNull() ||
|
||||
data["tnc"]["aprsBridgeActive"].isNull()) needsRewrite = true;
|
||||
data["tnc"]["aprsBridgeActive"].isNull() ||
|
||||
data["tnc"]["kissProtocol"].isNull()) needsRewrite = true;
|
||||
tnc.enableServer = data["tnc"]["enableServer"] | false;
|
||||
tnc.enableSerial = data["tnc"]["enableSerial"] | false;
|
||||
tnc.acceptOwn = data["tnc"]["acceptOwn"] | false;
|
||||
tnc.aprsBridgeActive = data["tnc"]["aprsBridgeActive"] | false;
|
||||
tnc.kissProtocol = data["tnc"]["kissProtocol"] | true;
|
||||
|
||||
if (data["mqtt"]["active"].isNull() ||
|
||||
data["mqtt"]["server"].isNull() ||
|
||||
@@ -538,6 +541,7 @@ void Configuration::setDefaultValues() {
|
||||
tnc.enableSerial = false;
|
||||
tnc.acceptOwn = false;
|
||||
tnc.aprsBridgeActive = false;
|
||||
tnc.kissProtocol = true;
|
||||
|
||||
mqtt.active = false;
|
||||
mqtt.server = "";
|
||||
|
||||
+56
-47
@@ -16,6 +16,7 @@
|
||||
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <WiFi.h>
|
||||
#include "configuration.h"
|
||||
#include "station_utils.h"
|
||||
@@ -29,6 +30,7 @@
|
||||
|
||||
extern Configuration Config;
|
||||
extern uint32_t lastScreenOn;
|
||||
extern APRSPacket lastAprsPacket;
|
||||
extern String iGateBeaconPacket;
|
||||
extern String firstLine;
|
||||
extern String secondLine;
|
||||
@@ -42,13 +44,32 @@ extern bool backupDigiMode;
|
||||
|
||||
namespace DIGI_Utils {
|
||||
|
||||
String cleanPath(String path) {
|
||||
String terms[] = {"WIDE1*,", "WIDE2*,", "*"};
|
||||
for (String term : terms) {
|
||||
int index = path.indexOf(term);
|
||||
if (index != -1) path.remove(index, term.length()); // less memory than: tempPath.replace("*", "");
|
||||
String cleanPath(const String& path) {
|
||||
String result;
|
||||
unsigned int start = 0;
|
||||
while (true) {
|
||||
int delim = path.indexOf(',', start);
|
||||
int end = (delim == -1) ? path.length() : delim;
|
||||
String token = path.substring(start, end);
|
||||
if (token != "WIDE1*" && token != "WIDE2*") {
|
||||
if (result.length() > 0) result += ",";
|
||||
result += token;
|
||||
}
|
||||
if (delim == -1) break;
|
||||
start = delim + 1;
|
||||
}
|
||||
return path;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int pathTokenIndex(const String& path, const String& token) {
|
||||
unsigned int start = 0;
|
||||
while (start < path.length()) {
|
||||
int end = path.indexOf(",", start);
|
||||
if (end == -1) end = path.length();
|
||||
if (path.substring(start, end) == token) return start;
|
||||
start = end + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
String processMode3Path(const String& path, const String& stationCallsign) {
|
||||
@@ -80,9 +101,9 @@ namespace DIGI_Utils {
|
||||
return tempPacket + "*" + path.substring(ownTokenEnd);
|
||||
}
|
||||
|
||||
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
|
||||
String buildPacket(const String& path, const String& packet, bool crossFreq) {
|
||||
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
String suffix = thirdParty ? ":}" : ":";
|
||||
String suffix = (lastAprsPacket.header != "") ? ":}" : ":";
|
||||
int suffixIndex = packet.indexOf(suffix);
|
||||
String packetToRepeat;
|
||||
if (!crossFreq) {
|
||||
@@ -94,12 +115,13 @@ namespace DIGI_Utils {
|
||||
tempPath.replace("WIDE1-1", stationCallsign + "*");
|
||||
} else if (tempPath.indexOf("WIDE2-") != -1 && digiMode == 2) { // WIDE2-n Digipeater
|
||||
tempPath = cleanPath(path);
|
||||
if (tempPath.indexOf("WIDE2-1") != -1) {
|
||||
tempPath.replace("WIDE2-1", stationCallsign + "*");
|
||||
} else if (tempPath.indexOf("WIDE2-2") != -1) {
|
||||
tempPath.replace("WIDE2-2", stationCallsign + "*,WIDE2-1");
|
||||
int idx = pathTokenIndex(tempPath, "WIDE2-1");
|
||||
if (idx != -1) {
|
||||
tempPath = tempPath.substring(0, idx) + stationCallsign + "*" + tempPath.substring(idx + 7);
|
||||
} else {
|
||||
return "";
|
||||
idx = pathTokenIndex(tempPath, "WIDE2-2");
|
||||
if (idx == -1) return "";
|
||||
tempPath = tempPath.substring(0, idx) + stationCallsign + "*,WIDE2-1" + tempPath.substring(idx + 7);
|
||||
}
|
||||
} else if (digiMode == 3) { // Repeat if station callsign is in path (free to repeat).
|
||||
tempPath = processMode3Path(tempPath, stationCallsign);
|
||||
@@ -114,13 +136,13 @@ namespace DIGI_Utils {
|
||||
packetToRepeat += stationCallsign;
|
||||
packetToRepeat += "*";
|
||||
}
|
||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(suffixIndex));
|
||||
packetToRepeat += APRSPacketLib::checkForStartingBytes(packet.substring(suffixIndex));
|
||||
return packetToRepeat;
|
||||
}
|
||||
|
||||
String generateDigipeatedPacket(const String& packet, bool thirdParty){
|
||||
String generateDigipeatedPacket(const String& packet){
|
||||
String temp;
|
||||
if (thirdParty) { // only header is used
|
||||
if (lastAprsPacket.header != "") { // thirdparty : only header is used
|
||||
const String& header = packet.substring(0, packet.indexOf(":}"));
|
||||
temp = header.substring(header.indexOf(">") + 1);
|
||||
} else {
|
||||
@@ -135,7 +157,7 @@ namespace DIGI_Utils {
|
||||
if (digiMode == 1 || backupDigiMode) {
|
||||
bool hasWide = path.indexOf("WIDE1-1") != -1;
|
||||
if (hasWide || crossFreq) {
|
||||
return buildPacket(path, packet, thirdParty, !hasWide);
|
||||
return buildPacket(path, packet, !hasWide);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -147,62 +169,49 @@ namespace DIGI_Utils {
|
||||
|
||||
if (hasWide1 && hasWide2 && wide2Index < wide1Index) return ""; // check that WIDE1 before WIDE2
|
||||
|
||||
if (hasWide1 || hasWide2) return buildPacket(path, packet, thirdParty, false); // regular APRS with WIDEn-N
|
||||
if (hasWide1 || hasWide2) return buildPacket(path, packet, false); // regular APRS with WIDEn-N
|
||||
|
||||
if (crossFreq) return buildPacket(path, packet, thirdParty, true); // CrossFreq (without WIDE)
|
||||
if (crossFreq) return buildPacket(path, packet, true); // CrossFreq (without WIDE)
|
||||
|
||||
return "";
|
||||
}
|
||||
if (digiMode == 3) {
|
||||
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
bool containsOwnCall = path.indexOf(stationCallsign) != -1;
|
||||
if (containsOwnCall) return buildPacket(path, packet, thirdParty, false);
|
||||
if (containsOwnCall) return buildPacket(path, packet, false);
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
if (commaIndex == -1 && (digiMode == 1 || backupDigiMode || digiMode == 2) && crossFreq) return buildPacket("", packet, thirdParty, true); // no "path" but is CrossFreq Digi
|
||||
if (commaIndex == -1 && (digiMode == 1 || backupDigiMode || digiMode == 2) && crossFreq) return buildPacket("", packet, true); // no "path" but is CrossFreq Digi
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void processLoRaPacket(const String& packet) {
|
||||
if (packet.indexOf("NOGATE") >= 0) return;
|
||||
if (lastAprsPacket.path.indexOf("NOGATE") >= 0) return;
|
||||
|
||||
bool thirdPartyPacket = false;
|
||||
String temp, Sender;
|
||||
int firstColonIndex = packet.indexOf(":");
|
||||
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] == '}' && packet.indexOf("TCPIP") > 0) { // 3rd Party
|
||||
thirdPartyPacket = true;
|
||||
temp = packet.substring(packet.indexOf(":}") + 2);
|
||||
Sender = temp.substring(0, temp.indexOf(">"));
|
||||
} else {
|
||||
temp = packet.substring(3);
|
||||
Sender = packet.substring(3, packet.indexOf(">"));
|
||||
}
|
||||
String temp = (lastAprsPacket.header != "") ? packet.substring(packet.indexOf(":}") + 2) : packet.substring(3);
|
||||
|
||||
String stationCallsign = Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign;
|
||||
if (Sender == stationCallsign) return; // Avoid listening to self packets
|
||||
if (!thirdPartyPacket && Config.tacticalCallsign == "" && !Utils::callsignIsValid(Sender)) return; // No thirdParty + no tactical y no valid callsign
|
||||
if (lastAprsPacket.sender == stationCallsign) return; // Avoid listening to self packets
|
||||
if (lastAprsPacket.header == "" && Config.tacticalCallsign == "" && !Utils::callsignIsValid(lastAprsPacket.sender)) return; // No thirdParty + no tactical y no valid callsign
|
||||
|
||||
if (STATION_Utils::isIn25SegHashBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) return;
|
||||
if (STATION_Utils::isIn25SegHashBuffer(lastAprsPacket.sender, temp.substring(temp.indexOf(":") + 2))) return;
|
||||
|
||||
STATION_Utils::updateLastHeard(Sender);
|
||||
Utils::typeOfPacket(temp, 2); // Digi
|
||||
bool queryMessage = false;
|
||||
int doubleColonIndex = temp.indexOf("::");
|
||||
if (doubleColonIndex > 10) { // it's a message
|
||||
String AddresseeAndMessage = temp.substring(doubleColonIndex + 2);
|
||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||
Addressee.trim();
|
||||
if (Addressee == stationCallsign) { // it's a message for me!
|
||||
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
|
||||
STATION_Utils::updateLastHeard(lastAprsPacket.sender);
|
||||
Utils::updateLoRaPacketDisplayInfo(lastAprsPacket, 1); // Digi
|
||||
bool queryMessage = false;
|
||||
if (lastAprsPacket.type == 1) { // MESSAGE
|
||||
if (lastAprsPacket.addressee == stationCallsign) { // it's a message for me!
|
||||
String AddresseeAndMessage = lastAprsPacket.addressee + ":" + lastAprsPacket.payload;
|
||||
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(lastAprsPacket.sender, APRSPacketLib::checkForStartingBytes(AddresseeAndMessage));
|
||||
}
|
||||
}
|
||||
if (queryMessage) return; // answer should not be repeated.
|
||||
|
||||
String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
|
||||
String loraPacket = generateDigipeatedPacket(packet.substring(3));
|
||||
if (loraPacket != "") {
|
||||
STATION_Utils::addToOutputPacketBuffer(loraPacket);
|
||||
if (Config.digi.ecoMode != 1) displayToggle(true);
|
||||
|
||||
+10
-7
@@ -57,19 +57,20 @@
|
||||
String lastEpaperText;
|
||||
#else
|
||||
#include <Adafruit_GFX.h>
|
||||
#if defined RPC_LORA_DIGIGATE_1W
|
||||
#define SCREEN_HEIGHT 32
|
||||
#else
|
||||
#define SCREEN_HEIGHT 64
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SH1106
|
||||
#include <Adafruit_SH110X.h>
|
||||
Adafruit_SH1106G display(128, 64, &Wire, OLED_RST);
|
||||
Adafruit_SH1106G display(128, SCREEN_HEIGHT, &Wire, OLED_RST);
|
||||
#else
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#ifdef HELTEC_WSL_V3_DISPLAY
|
||||
Adafruit_SSD1306 display(128, 64, &Wire1, OLED_RST);
|
||||
Adafruit_SSD1306 display(128, SCREEN_HEIGHT, &Wire1, OLED_RST);
|
||||
#else
|
||||
#if defined RPC_LORA_DIGIGATE_1W
|
||||
#define SCREEN_HEIGHT 32
|
||||
#else
|
||||
#define SCREEN_HEIGHT 64
|
||||
#endif
|
||||
Adafruit_SSD1306 display(128, SCREEN_HEIGHT, &Wire, OLED_RST);
|
||||
#endif
|
||||
#endif
|
||||
@@ -107,6 +108,8 @@ void displaySetup() {
|
||||
maxLines = 6;
|
||||
#elif (SCREEN_HEIGHT == 32)
|
||||
maxLines = 3;
|
||||
#else
|
||||
maxLines = 6;
|
||||
#endif
|
||||
#ifdef HAS_EPAPER
|
||||
display.landscape();
|
||||
|
||||
@@ -101,100 +101,6 @@ namespace GPS_Utils {
|
||||
|
||||
}
|
||||
|
||||
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 infoGPS;
|
||||
if (indexOfExclamation > 10) {
|
||||
infoGPS = packet.substring(indexOfExclamation + OFFSET);
|
||||
} else if (indexOfEqual > 10) {
|
||||
infoGPS = packet.substring(indexOfEqual + OFFSET);
|
||||
}
|
||||
|
||||
float decodedLatitude = APRSPacketLib::decodeBase91EncodedLatitude(infoGPS.substring(0,4));
|
||||
float decodedLongitude = APRSPacketLib::decodeBase91EncodedLongitude(infoGPS.substring(4,8));
|
||||
|
||||
return buildDistanceAndComment(decodedLatitude, decodedLongitude, infoGPS.substring(12));
|
||||
}
|
||||
|
||||
String getReceivedGPS(const String& packet) {
|
||||
int indexOfExclamation = packet.indexOf(":!");
|
||||
int indexOfEqual = packet.indexOf(":=");
|
||||
int indexOfAt = packet.indexOf(":@");
|
||||
|
||||
String infoGPS;
|
||||
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)
|
||||
}
|
||||
|
||||
String Latitude = infoGPS.substring(0,8); // First 8 characters are Latitude
|
||||
int latitudeColonIndex = Latitude.indexOf(".");
|
||||
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(latitudeColonIndex + 1, latitudeColonIndex + 3).toFloat() / (60*100);
|
||||
if (Latitude.endsWith("S")) convertedLatitude = -convertedLatitude; // Handle Southern Hemisphere
|
||||
|
||||
String Longitude = infoGPS.substring(9,18); // Next 9 characters are Longitude
|
||||
int longitudeColonIndex = Longitude.indexOf(".");
|
||||
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(longitudeColonIndex + 1, longitudeColonIndex + 3).toFloat() / (60*100);
|
||||
if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere
|
||||
|
||||
return buildDistanceAndComment(convertedLatitude, convertedLongitude, infoGPS.substring(19));
|
||||
}
|
||||
|
||||
String getDistanceAndComment(const String& packet) {
|
||||
int indexOfAt = packet.indexOf(":@");
|
||||
if (indexOfAt > 10) return getReceivedGPS(packet);
|
||||
|
||||
const uint8_t nonEncondedLatitudeOffset = 9; // "N" / "S"
|
||||
const uint8_t nonEncondedLongitudeOffset = 19; // "E" / "W"
|
||||
const uint8_t encodedByteOffset = 14;
|
||||
|
||||
int indexOfExclamation = packet.indexOf(":!");
|
||||
int indexOfEqual = packet.indexOf(":=");
|
||||
int baseIndex = - 1;
|
||||
if (indexOfExclamation > 10) {
|
||||
baseIndex = indexOfExclamation;
|
||||
} else if (indexOfEqual > 10) {
|
||||
baseIndex = indexOfEqual;
|
||||
}
|
||||
if (baseIndex == -1) return " _ / _ / _ ";
|
||||
|
||||
int latitudeIndex = baseIndex + nonEncondedLatitudeOffset;
|
||||
int longitudeIndex = baseIndex + nonEncondedLongitudeOffset;
|
||||
int encodedByteIndex = baseIndex + encodedByteOffset;
|
||||
int packetLength = packet.length();
|
||||
|
||||
if (latitudeIndex < packetLength && longitudeIndex < packetLength) {
|
||||
char latChar = packet[latitudeIndex];
|
||||
char lngChar = packet[longitudeIndex];
|
||||
if ((latChar == 'N' || latChar == 'S') && (lngChar == 'E' || lngChar == 'W')) return getReceivedGPS(packet);
|
||||
}
|
||||
if (encodedByteIndex < packetLength) {
|
||||
char byteChar = packet[encodedByteIndex];
|
||||
if (byteChar == 'G' || byteChar == 'Q' || byteChar == '[' || byteChar == 'H' || byteChar == 'X' || byteChar == '3') return decodeEncodedGPS(packet);
|
||||
}
|
||||
return " _ / _ / _ ";
|
||||
}
|
||||
|
||||
/*String getDistanceAndCommentFromMicE(const String& packet) {
|
||||
int indexOfMicE1 = packet.indexOf(":`");
|
||||
int indexOfMicE2 = packet.indexOf(":\'");
|
||||
|
||||
if (indexOfMicE1 > 10 || indexOfMicE2 > 10) {
|
||||
return decodeEncodedGPS(packet);
|
||||
}
|
||||
return " _ / _ / _ ";
|
||||
}*/
|
||||
|
||||
void setup() {
|
||||
#ifdef HAS_GPS
|
||||
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) {
|
||||
|
||||
+8
-8
@@ -65,6 +65,7 @@ int backoffMax = 4; // Max Backoff value (number of CAD slots to wai
|
||||
|
||||
int rssi, freqError;
|
||||
float snr;
|
||||
APRSPacket lastAprsPacket;
|
||||
|
||||
|
||||
namespace LoRa_Utils {
|
||||
@@ -230,7 +231,7 @@ namespace LoRa_Utils {
|
||||
transmitFlag = true;
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX
|
||||
SYSLOG_Utils::logLoRaTx(newPacket);
|
||||
}
|
||||
Utils::print("---> LoRa Packet Tx : ");
|
||||
Utils::println(newPacket);
|
||||
@@ -276,9 +277,9 @@ namespace LoRa_Utils {
|
||||
rssi = radio.getRSSI();
|
||||
snr = radio.getSNR();
|
||||
freqError = radio.getFrequencyError();
|
||||
Utils::println("<--- LoRa Packet Rx : " + packet.substring(3));
|
||||
Utils::println("(RSSI:" + String(rssi) + " / SNR:" + String(snr) + " / FreqErr:" + String(freqError) + ")");
|
||||
Utils::println("<--- LoRa Packet Rx (RSSI:" + String(rssi) + " | SNR:" + String(snr) + " | FreqErr:" + String(freqError) + ") : " + packet.substring(3));
|
||||
|
||||
lastAprsPacket = APRSPacketLib::processReceivedPacket(packet.substring(3), rssi, snr, freqError);
|
||||
if (Config.digi.ecoMode == 0) {
|
||||
if (receivedPackets.size() >= 10) {
|
||||
receivedPackets.erase(receivedPackets.begin());
|
||||
@@ -290,14 +291,13 @@ namespace LoRa_Utils {
|
||||
receivedPacket.SNR = snr;
|
||||
receivedPackets.push_back(receivedPacket);
|
||||
|
||||
APRSPacket aprsPacket = APRSPacketLib::processReceivedPacket(packet.substring(3), rssi, snr, freqError);
|
||||
if (aprsPacket.type == 0 || aprsPacket.type == 4) { // 0 = GPS, 4 = Mic-E (only ones with position)
|
||||
MAP_Utils::upsert(aprsPacket.sender, aprsPacket.latitude, aprsPacket.longitude, aprsPacket.path, aprsPacket.overlay + aprsPacket.symbol, aprsPacket.rssi, aprsPacket.snr);
|
||||
if (lastAprsPacket.type == 0 || lastAprsPacket.type == 4) { // 0 = GPS, 4 = Mic-E (only ones with position)
|
||||
MAP_Utils::upsert(lastAprsPacket.sender, lastAprsPacket.latitude, lastAprsPacket.longitude, lastAprsPacket.path, lastAprsPacket.overlay + lastAprsPacket.symbol, lastAprsPacket.rssi, lastAprsPacket.snr);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX
|
||||
SYSLOG_Utils::logLoRaRx(lastAprsPacket, packet, rssi, snr, freqError); // RX
|
||||
}
|
||||
} else {
|
||||
packet = "";
|
||||
@@ -310,7 +310,7 @@ namespace LoRa_Utils {
|
||||
freqError = radio.getFrequencyError();
|
||||
Utils::println(F("CRC error!"));
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC
|
||||
SYSLOG_Utils::logCRCError(packet, rssi, snr, freqError);
|
||||
}
|
||||
packet = "";
|
||||
} else {
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace MAP_Utils {
|
||||
s.count++;
|
||||
symbol.toCharArray(s.symbol, sizeof(s.symbol));
|
||||
path.toCharArray(s.path, sizeof(s.path));
|
||||
if (path.indexOf('*') == -1) s.heardDirect = true; // se oyo directo alguna vez; no se resetea si despues llega repetido
|
||||
writeFormatedTime(s.lastHeard, sizeof(s.lastHeard));
|
||||
s.lastHeardMillis = millis();
|
||||
return;
|
||||
@@ -73,6 +74,7 @@ namespace MAP_Utils {
|
||||
st.rssi = rssi;
|
||||
st.snr = snr;
|
||||
st.count = 1;
|
||||
st.heardDirect = (path.indexOf('*') == -1); // primer paquete: directo si no trae digis usados
|
||||
writeFormatedTime(st.lastHeard, sizeof(st.lastHeard));
|
||||
st.lastHeardMillis = millis();
|
||||
mapStations.push_back(st);
|
||||
@@ -101,6 +103,7 @@ namespace MAP_Utils {
|
||||
data[i]["count"] = mapStations[i].count;
|
||||
data[i]["lastHeard"] = mapStations[i].lastHeard;
|
||||
data[i]["path"] = mapStations[i].path;
|
||||
data[i]["heardDirect"] = mapStations[i].heardDirect;
|
||||
}
|
||||
|
||||
String buffer;
|
||||
|
||||
+132
-98
@@ -16,6 +16,7 @@
|
||||
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
@@ -30,117 +31,150 @@ extern String versionNumber;
|
||||
|
||||
WiFiUDP udpClient;
|
||||
|
||||
namespace {
|
||||
|
||||
String createSyslogStart() {
|
||||
String syslogStartPacket = "<165>1 - ";
|
||||
syslogStartPacket.concat(Config.callsign);
|
||||
syslogStartPacket.concat(" CA2RXU_LoRa_iGate_");
|
||||
syslogStartPacket.concat(versionNumber);
|
||||
syslogStartPacket.concat(" - - - "); //RFC5424 The Syslog Protocol
|
||||
return syslogStartPacket;
|
||||
}
|
||||
|
||||
void sendSyslogPacket(const String& syslogPacket) {
|
||||
udpClient.beginPacket(Config.syslog.server.c_str(), Config.syslog.port);
|
||||
udpClient.write((const uint8_t*)syslogPacket.c_str(), syslogPacket.length());
|
||||
udpClient.endPacket();
|
||||
}
|
||||
|
||||
String formatSignalData(int rssi, float snr, int freqError) {
|
||||
char signalData[35];
|
||||
snprintf(signalData, sizeof(signalData), " / %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
|
||||
return String(signalData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace SYSLOG_Utils {
|
||||
|
||||
void log(const uint8_t type, const String& packet, const int rssi, const float snr, const int freqError) {
|
||||
void logLoRaRx(APRSPacket& aprsPacket, const String& packet, const int rssi, const float snr, const int freqError) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
String syslogPacket = "<165>1 - ";
|
||||
syslogPacket.concat(Config.callsign);
|
||||
syslogPacket.concat(" CA2RXU_LoRa_iGate_");
|
||||
syslogPacket.concat(versionNumber);
|
||||
syslogPacket.concat(" - - - "); //RFC5424 The Syslog Protocol
|
||||
String syslogPacket = createSyslogStart();
|
||||
syslogPacket.concat("RX / ");
|
||||
|
||||
char signalData[35];
|
||||
snprintf(signalData, sizeof(signalData), " / %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
|
||||
|
||||
int colonIndex = packet.indexOf(":");
|
||||
char nextChar = packet[colonIndex + 1];
|
||||
int greaterThanIndex = packet.indexOf(">");
|
||||
int telemetryPacketIndex = packet.indexOf(":T#");
|
||||
String sender = packet.substring(3, greaterThanIndex);
|
||||
|
||||
switch (type) {
|
||||
case 0: // CRC
|
||||
syslogPacket.concat("CRC / CRC-ERROR / ");
|
||||
syslogPacket.concat(packet);
|
||||
syslogPacket.concat(signalData);
|
||||
switch (aprsPacket.type) {
|
||||
case 1: // MESSAGE
|
||||
syslogPacket.concat("MESSAGE / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(aprsPacket.addressee);
|
||||
syslogPacket.concat(":");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
break;
|
||||
case 1: // RX
|
||||
syslogPacket.concat("RX / ");
|
||||
if (nextChar == ':') {
|
||||
syslogPacket.concat("MESSAGE / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
|
||||
syslogPacket.concat("GPS / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" / ");
|
||||
if (packet.indexOf("WIDE1-1") > 10) {
|
||||
syslogPacket.concat(packet.substring(greaterThanIndex + 1, packet.indexOf(",")));
|
||||
syslogPacket.concat(" / WIDE1-1");
|
||||
} else {
|
||||
syslogPacket.concat(packet.substring(greaterThanIndex + 1, colonIndex));
|
||||
syslogPacket.concat(" / -");
|
||||
case 0: // GPS
|
||||
syslogPacket.concat("GPS / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" / ");
|
||||
if (aprsPacket.path.indexOf("WIDE1-1") != -1) {
|
||||
syslogPacket.concat(aprsPacket.tocall);
|
||||
syslogPacket.concat(" / WIDE1-1");
|
||||
} else {
|
||||
syslogPacket.concat(aprsPacket.tocall);
|
||||
if (aprsPacket.path != "") {
|
||||
syslogPacket.concat(",");
|
||||
syslogPacket.concat(aprsPacket.path);
|
||||
}
|
||||
} else if (nextChar == '>') {
|
||||
syslogPacket.concat("STATUS / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (nextChar == '`' || nextChar == '\'') { // both Mic-E DTIs are valid
|
||||
syslogPacket.concat("MIC-E / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(String(nextChar)); // restore the actual indicator received
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
// append distance for Mic-E, same as the GPS path
|
||||
//syslogPacket.concat(" / ");
|
||||
//syslogPacket.concat(GPS_Utils::getDistanceAndComment(packet));
|
||||
} else if (nextChar == ';') {
|
||||
syslogPacket.concat("OBJECT / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (telemetryPacketIndex >= 10 && packet.indexOf(":=/") == -1) {
|
||||
syslogPacket.concat("TELEMETRY / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(telemetryPacketIndex + 3));
|
||||
} else {
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
syslogPacket.concat(signalData);
|
||||
if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
|
||||
syslogPacket.concat(" / ");
|
||||
syslogPacket.concat(GPS_Utils::getDistanceAndComment(packet));
|
||||
syslogPacket.concat(" / -");
|
||||
}
|
||||
break;
|
||||
case 2: // APRSIS TX
|
||||
syslogPacket.concat("APRSIS TX / ");
|
||||
if (nextChar == '>') {
|
||||
syslogPacket.concat("StartUp_Status / ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (nextChar == ':') {
|
||||
syslogPacket.concat("QUERY / ");
|
||||
syslogPacket.concat(packet);
|
||||
} else {
|
||||
syslogPacket.concat("BEACON / ");
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
case 2: // STATUS
|
||||
syslogPacket.concat("STATUS / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
break;
|
||||
case 3: // TX
|
||||
syslogPacket.concat("TX / ");
|
||||
if (packet.indexOf("RFONLY") > 10) {
|
||||
syslogPacket.concat("RFONLY / ");
|
||||
syslogPacket.concat(packet);
|
||||
} else if (nextChar == ':') {
|
||||
syslogPacket.concat("MESSAGE / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else {
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
case 4: // MIC-E
|
||||
syslogPacket.concat("MIC-E / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.indexOf(":`") != -1 ? "`" : "'"); // restore the actual indicator received
|
||||
break;
|
||||
default:
|
||||
syslogPacket = "<165>1 - ERROR LoRa - - - ERROR / Error in Syslog Packet"; //RFC5424 The Syslog Protocol
|
||||
case 5: // OBJECT
|
||||
syslogPacket.concat("OBJECT / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
break;
|
||||
case 3: // TELEMETRY
|
||||
syslogPacket.concat("TELEMETRY / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
break;
|
||||
default: // type == 6, unrecognized -- payload is the full, uncut packet
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
break;
|
||||
}
|
||||
udpClient.beginPacket(Config.syslog.server.c_str(), Config.syslog.port);
|
||||
udpClient.write((const uint8_t*)syslogPacket.c_str(), syslogPacket.length());
|
||||
udpClient.endPacket();
|
||||
syslogPacket.concat(formatSignalData(rssi, snr, freqError));
|
||||
if (aprsPacket.type == 0 || aprsPacket.type == 4) { // GPS or Mic-E -- both already carry
|
||||
syslogPacket.concat(" / "); // clean lat/lon + comment in aprsPacket
|
||||
syslogPacket.concat(GPS_Utils::buildDistanceAndComment(aprsPacket.latitude, aprsPacket.longitude, aprsPacket.payload));
|
||||
}
|
||||
sendSyslogPacket(syslogPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void logAPRSISTx(const String& packet) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
String syslogPacket = createSyslogStart();
|
||||
syslogPacket.concat("APRSIS TX / ");
|
||||
|
||||
APRSPacket aprsPacket = APRSPacketLib::processReceivedPacket(packet, 0, 0, 0);
|
||||
if (aprsPacket.type == 2) { // STATUS
|
||||
syslogPacket.concat("StartUp_Status / ");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
} else if (aprsPacket.type == 1) { // MESSAGE
|
||||
syslogPacket.concat("QUERY / ");
|
||||
syslogPacket.concat(packet);
|
||||
} else {
|
||||
syslogPacket.concat("BEACON / ");
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
sendSyslogPacket(syslogPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void logLoRaTx(const String& packet) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
String syslogPacket = createSyslogStart();
|
||||
syslogPacket.concat("TX / ");
|
||||
|
||||
APRSPacket aprsPacket = APRSPacketLib::processReceivedPacket(packet, 0, 0, 0);
|
||||
if (aprsPacket.path.indexOf("RFONLY") != -1) {
|
||||
syslogPacket.concat("RFONLY / ");
|
||||
syslogPacket.concat(packet);
|
||||
} else if (aprsPacket.type == 1) {
|
||||
syslogPacket.concat("MESSAGE / ");
|
||||
syslogPacket.concat(aprsPacket.sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(aprsPacket.addressee);
|
||||
syslogPacket.concat(":");
|
||||
syslogPacket.concat(aprsPacket.payload);
|
||||
} else {
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
sendSyslogPacket(syslogPacket);
|
||||
}
|
||||
}
|
||||
|
||||
void logCRCError(const String& packet, const int rssi, const float snr, const int freqError) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
String syslogPacket = createSyslogStart();
|
||||
syslogPacket.concat("CRC / CRC-ERROR / ");
|
||||
syslogPacket.concat(packet);
|
||||
syslogPacket.concat(formatSignalData(rssi, snr, freqError));
|
||||
sendSyslogPacket(syslogPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+51
-17
@@ -78,7 +78,23 @@ namespace TNC_Utils {
|
||||
}
|
||||
}
|
||||
|
||||
void handleInputData(char character, int bufferIndex) {
|
||||
void processInputFrame(const String& frame, int bufferIndex, const String& protocolLabel) {
|
||||
if (bufferIndex != -1) {
|
||||
Utils::print("<--- Got from TNC (" + protocolLabel + ") : ");
|
||||
Utils::println(frame);
|
||||
}
|
||||
|
||||
String sender = frame.substring(0,frame.indexOf(">"));
|
||||
|
||||
if (Config.tnc.acceptOwn || sender != Config.callsign) {
|
||||
if (Config.loramodule.txActive) STATION_Utils::addToOutputPacketBuffer(frame);
|
||||
if (Config.tnc.aprsBridgeActive && Config.aprs_is.active && passcodeValid && aprsIsClient.connected()) APRS_IS_Utils::upload(frame);
|
||||
} else {
|
||||
Utils::println("Ignored own frame from " + protocolLabel);
|
||||
}
|
||||
}
|
||||
|
||||
void handleInputDataKISS(char character, int bufferIndex) {
|
||||
String* data = (bufferIndex == -1) ? &inputSerialBuffer : &inputServerBuffer[bufferIndex];
|
||||
if (data->length() == 0 && character != (char)FEND) return;
|
||||
|
||||
@@ -89,19 +105,7 @@ namespace TNC_Utils {
|
||||
const String& frame = decodeKISS(*data, isDataFrame);
|
||||
|
||||
if (isDataFrame) {
|
||||
if (bufferIndex != -1) {
|
||||
Utils::print("<--- Got from TNC : ");
|
||||
Utils::println(frame);
|
||||
}
|
||||
|
||||
String sender = frame.substring(0,frame.indexOf(">"));
|
||||
|
||||
if (Config.tnc.acceptOwn || sender != Config.callsign) {
|
||||
if (Config.loramodule.txActive) STATION_Utils::addToOutputPacketBuffer(frame);
|
||||
if (Config.tnc.aprsBridgeActive && Config.aprs_is.active && passcodeValid && aprsIsClient.connected()) APRS_IS_Utils::upload(frame);
|
||||
} else {
|
||||
Utils::println("Ignored own frame from KISS");
|
||||
}
|
||||
processInputFrame(frame, bufferIndex, "KISS");
|
||||
}
|
||||
data->clear();
|
||||
}
|
||||
@@ -111,6 +115,36 @@ namespace TNC_Utils {
|
||||
}
|
||||
}
|
||||
|
||||
void handleInputDataTNC2(char character, int bufferIndex) {
|
||||
String* data = (bufferIndex == -1) ? &inputSerialBuffer : &inputServerBuffer[bufferIndex];
|
||||
|
||||
if (character == '\r') return;
|
||||
|
||||
if (character == '\n') {
|
||||
String frame = *data;
|
||||
frame.trim();
|
||||
data->clear();
|
||||
|
||||
if (frame.length() > 0 && frame.indexOf(':') != -1 && frame.indexOf('>') != -1) {
|
||||
processInputFrame(frame, bufferIndex, "TNC2");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
data->concat(character);
|
||||
if (data->length() > 255) {
|
||||
data->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void handleInputData(char character, int bufferIndex) {
|
||||
if (Config.tnc.kissProtocol) {
|
||||
handleInputDataKISS(character, bufferIndex);
|
||||
} else {
|
||||
handleInputDataTNC2(character, bufferIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void readFromClients() {
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
auto client = clients[i];
|
||||
@@ -138,13 +172,13 @@ namespace TNC_Utils {
|
||||
void sendToClients(const String& packet, bool stripBytes) {
|
||||
String cleanPacket = stripBytes ? packet.substring(3): packet;
|
||||
|
||||
const String kissEncoded = encodeKISS(cleanPacket);
|
||||
const String encoded = Config.tnc.kissProtocol ? encodeKISS(cleanPacket) : (cleanPacket + "\r\n");
|
||||
|
||||
for (int i = 0; i < MAX_CLIENTS; i++) {
|
||||
auto client = clients[i];
|
||||
if (client != nullptr) {
|
||||
if (client->connected()) {
|
||||
client->print(kissEncoded);
|
||||
client->print(encoded);
|
||||
client->flush();
|
||||
} else {
|
||||
delete client;
|
||||
@@ -158,7 +192,7 @@ namespace TNC_Utils {
|
||||
|
||||
void sendToSerial(const String& packet, bool stripBytes) {
|
||||
String cleanPacket = stripBytes ? packet.substring(3): packet;
|
||||
Serial.print(encodeKISS(cleanPacket));
|
||||
Serial.print(Config.tnc.kissProtocol ? encodeKISS(cleanPacket) : (cleanPacket + "\r\n"));
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
|
||||
+56
-37
@@ -89,7 +89,7 @@ namespace Utils {
|
||||
|
||||
if (sendOverAPRSIS) {
|
||||
APRS_IS_Utils::upload(statusPacket);
|
||||
SYSLOG_Utils::log(2, statusPacket, 0, 0.0, 0); // APRSIS TX
|
||||
SYSLOG_Utils::logAPRSISTx(statusPacket);
|
||||
} else {
|
||||
STATION_Utils::addToOutputPacketBuffer(statusPacket, true); // treated also as beacon on Tx Freq
|
||||
}
|
||||
@@ -288,7 +288,7 @@ namespace Utils {
|
||||
#else
|
||||
APRS_IS_Utils::upload(beaconPacket);
|
||||
#endif
|
||||
if (Config.syslog.logBeaconOverTCPIP) SYSLOG_Utils::log(1, "tcp" + beaconPacket, 0, 0.0, 0); // APRSIS TX
|
||||
if (Config.syslog.logBeaconOverTCPIP) SYSLOG_Utils::logAPRSISTx(beaconPacket);
|
||||
}
|
||||
|
||||
if (Config.beacon.sendViaRF || backupDigiMode) {
|
||||
@@ -325,21 +325,65 @@ namespace Utils {
|
||||
}
|
||||
}
|
||||
|
||||
void typeOfPacket(const String& packet, const uint8_t packetType) {
|
||||
void updateLoRaPacketDisplayInfo(APRSPacket& aprsPacket, const uint8_t packetType) {
|
||||
switch (packetType) {
|
||||
case 0: // LoRa-APRS
|
||||
fifthLine = "LoRa Rx ----> APRS-IS";
|
||||
break;
|
||||
case 1: // APRS-LoRa
|
||||
fifthLine = "APRS-IS ----> LoRa Tx";
|
||||
break;
|
||||
case 2: // Digipeater
|
||||
case 1: // Digipeater
|
||||
fifthLine = "LoRa Rx ----> LoRa Tx";
|
||||
break;
|
||||
}
|
||||
|
||||
int firstColonIndex = packet.indexOf(":");
|
||||
char nextChar = packet[firstColonIndex + 1];
|
||||
String sender = aprsPacket.sender;
|
||||
for (int i = sender.length(); i < 9; i++) {
|
||||
sender += " ";
|
||||
}
|
||||
sixthLine = sender;
|
||||
|
||||
switch (aprsPacket.type) {
|
||||
case 1: // MESSAGE
|
||||
sixthLine += "> MESSAGE";
|
||||
break;
|
||||
case 2: // STATUS
|
||||
sixthLine += "> NEW STATUS";
|
||||
break;
|
||||
case 0: // GPS
|
||||
sixthLine += "> GPS BEACON";
|
||||
if (!Config.syslog.active) GPS_Utils::buildDistanceAndComment(aprsPacket.latitude, aprsPacket.longitude, aprsPacket.payload);
|
||||
seventhLine = "RSSI:";
|
||||
seventhLine += String(rssi);
|
||||
seventhLine += "dBm";
|
||||
seventhLine += (rssi <= -100) ? " " : " ";
|
||||
if (distance.indexOf(".") == 1) seventhLine += " ";
|
||||
seventhLine += "D:";
|
||||
seventhLine += distance;
|
||||
seventhLine += "km";
|
||||
break;
|
||||
case 3: // TELEMETRY
|
||||
sixthLine += "> TELEMETRY";
|
||||
break;
|
||||
case 4: // MIC-E
|
||||
sixthLine += "> MIC-E";
|
||||
break;
|
||||
case 5: // OBJECT
|
||||
sixthLine += "> OBJECT";
|
||||
break;
|
||||
default: // unrecognized
|
||||
sixthLine += "> ?????????";
|
||||
break;
|
||||
}
|
||||
if (aprsPacket.type != 0) { // Common assignment for non-GPS cases
|
||||
seventhLine = "RSSI:";
|
||||
seventhLine += String(rssi);
|
||||
seventhLine += "dBm SNR: ";
|
||||
seventhLine += String(snr);
|
||||
seventhLine += "dBm";
|
||||
}
|
||||
}
|
||||
|
||||
void updateAPRSISPacketDisplayInfo(const String& packet) {
|
||||
fifthLine = "APRS-IS ----> LoRa Tx";
|
||||
|
||||
String sender = packet.substring(0,packet.indexOf(">"));
|
||||
for (int i = sender.length(); i < 9; i++) {
|
||||
@@ -347,37 +391,12 @@ namespace Utils {
|
||||
}
|
||||
sixthLine = sender;
|
||||
|
||||
if (nextChar == ':') {
|
||||
if (packet.indexOf("::") > 0) {
|
||||
sixthLine += "> MESSAGE";
|
||||
} else if (nextChar == '>') {
|
||||
sixthLine += "> NEW STATUS";
|
||||
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
|
||||
sixthLine += "> GPS BEACON";
|
||||
if (!Config.syslog.active) GPS_Utils::getDistanceAndComment(packet); // to be checked!!!
|
||||
seventhLine = "RSSI:";
|
||||
seventhLine += String(rssi);
|
||||
seventhLine += "dBm";
|
||||
seventhLine += (rssi <= -100) ? " " : " ";
|
||||
if (distance.indexOf(".") == 1) seventhLine += " ";
|
||||
seventhLine += "D:";
|
||||
seventhLine += distance;
|
||||
seventhLine += "km";
|
||||
} else if (nextChar == '`' || nextChar == '\'') {
|
||||
sixthLine += "> MIC-E";
|
||||
} else if (nextChar == ';') {
|
||||
sixthLine += "> OBJECT";
|
||||
} else if (packet.indexOf(":T#") >= 10 && packet.indexOf(":=/") == -1) {
|
||||
sixthLine += "> TELEMETRY";
|
||||
} else {
|
||||
sixthLine += "> ??????????";
|
||||
}
|
||||
if (nextChar != '!' && nextChar != '=' && nextChar != '@') { // Common assignment for non-GPS cases
|
||||
seventhLine = "RSSI:";
|
||||
seventhLine += String(rssi);
|
||||
seventhLine += "dBm SNR: ";
|
||||
seventhLine += String(snr);
|
||||
seventhLine += "dBm";
|
||||
sixthLine += "> OBJECT";
|
||||
}
|
||||
seventhLine = "";
|
||||
}
|
||||
|
||||
void print(const String& text) {
|
||||
|
||||
+22
-21
@@ -62,17 +62,17 @@ extern const unsigned char favicon_data[] asm("_binary_data_embed_favicon_png_gz
|
||||
extern const unsigned char favicon_data_end[] asm("_binary_data_embed_favicon_png_gz_end");
|
||||
extern const size_t favicon_data_len = favicon_data_end - favicon_data;
|
||||
|
||||
extern const unsigned char aprs_symbols_48_0_data[] asm("_binary_data_embed_aprs_symbols_48_0_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_48_0_data_end[] asm("_binary_data_embed_aprs_symbols_48_0_png_gz_end");
|
||||
extern const size_t aprs_symbols_48_0_data_len = aprs_symbols_48_0_data_end - aprs_symbols_48_0_data;
|
||||
extern const unsigned char aprs_symbols_24_0_data[] asm("_binary_data_embed_aprs_symbols_24_0_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_24_0_data_end[] asm("_binary_data_embed_aprs_symbols_24_0_png_gz_end");
|
||||
extern const size_t aprs_symbols_24_0_data_len = aprs_symbols_24_0_data_end - aprs_symbols_24_0_data;
|
||||
|
||||
extern const unsigned char aprs_symbols_48_1_data[] asm("_binary_data_embed_aprs_symbols_48_1_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_48_1_data_end[] asm("_binary_data_embed_aprs_symbols_48_1_png_gz_end");
|
||||
extern const size_t aprs_symbols_48_1_data_len = aprs_symbols_48_1_data_end - aprs_symbols_48_1_data;
|
||||
extern const unsigned char aprs_symbols_24_1_data[] asm("_binary_data_embed_aprs_symbols_24_1_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_24_1_data_end[] asm("_binary_data_embed_aprs_symbols_24_1_png_gz_end");
|
||||
extern const size_t aprs_symbols_24_1_data_len = aprs_symbols_24_1_data_end - aprs_symbols_24_1_data;
|
||||
|
||||
extern const unsigned char aprs_symbols_48_2_data[] asm("_binary_data_embed_aprs_symbols_48_2_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_48_2_data_end[] asm("_binary_data_embed_aprs_symbols_48_2_png_gz_end");
|
||||
extern const size_t aprs_symbols_48_2_data_len = aprs_symbols_48_2_data_end - aprs_symbols_48_2_data;
|
||||
extern const unsigned char aprs_symbols_24_2_data[] asm("_binary_data_embed_aprs_symbols_24_2_png_gz_start");
|
||||
extern const unsigned char aprs_symbols_24_2_data_end[] asm("_binary_data_embed_aprs_symbols_24_2_png_gz_end");
|
||||
extern const size_t aprs_symbols_24_2_data_len = aprs_symbols_24_2_data_end - aprs_symbols_24_2_data;
|
||||
|
||||
|
||||
namespace WEB_Utils {
|
||||
@@ -104,36 +104,36 @@ namespace WEB_Utils {
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleAprsSymbols48Primary(AsyncWebServerRequest *request) {
|
||||
void handleAprsSymbols24Primary(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(
|
||||
200,
|
||||
"image/png",
|
||||
(const uint8_t*)aprs_symbols_48_0_data,
|
||||
aprs_symbols_48_0_data_len
|
||||
(const uint8_t*)aprs_symbols_24_0_data,
|
||||
aprs_symbols_24_0_data_len
|
||||
);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response->addHeader("Cache-Control", "max-age=3600");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleAprsSymbols48Alternate(AsyncWebServerRequest *request) {
|
||||
void handleAprsSymbols24Alternate(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(
|
||||
200,
|
||||
"image/png",
|
||||
(const uint8_t*)aprs_symbols_48_1_data,
|
||||
aprs_symbols_48_1_data_len
|
||||
(const uint8_t*)aprs_symbols_24_1_data,
|
||||
aprs_symbols_24_1_data_len
|
||||
);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response->addHeader("Cache-Control", "max-age=3600");
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void handleAprsSymbols48Overlay(AsyncWebServerRequest *request) {
|
||||
void handleAprsSymbols24Overlay(AsyncWebServerRequest *request) {
|
||||
AsyncWebServerResponse *response = request->beginResponse(
|
||||
200,
|
||||
"image/png",
|
||||
(const uint8_t*)aprs_symbols_48_2_data,
|
||||
aprs_symbols_48_2_data_len
|
||||
(const uint8_t*)aprs_symbols_24_2_data,
|
||||
aprs_symbols_24_2_data_len
|
||||
);
|
||||
response->addHeader("Content-Encoding", "gzip");
|
||||
response->addHeader("Cache-Control", "max-age=3600");
|
||||
@@ -322,6 +322,7 @@ namespace WEB_Utils {
|
||||
Config.tnc.enableSerial = request->hasParam("tnc.enableSerial", true);
|
||||
Config.tnc.acceptOwn = request->hasParam("tnc.acceptOwn", true);
|
||||
Config.tnc.aprsBridgeActive = request->hasParam("tnc.aprsBridgeActive", true);
|
||||
Config.tnc.kissProtocol = getParamStringSafe("tnc.kissProtocol", Config.tnc.kissProtocol ? "KISS" : "TNC2") != "TNC2";
|
||||
|
||||
Config.mqtt.active = request->hasParam("mqtt.active", true);
|
||||
if (Config.mqtt.active) {
|
||||
@@ -449,9 +450,9 @@ namespace WEB_Utils {
|
||||
server.on("/leaflet.css", HTTP_GET, handleLeafletStyle);
|
||||
server.on("/leaflet.js", HTTP_GET, handleLeafletScript);
|
||||
server.on("/favicon.png", HTTP_GET, handleFavicon);
|
||||
server.on("/aprs-symbols-48-0.png", HTTP_GET, handleAprsSymbols48Primary);
|
||||
server.on("/aprs-symbols-48-1.png", HTTP_GET, handleAprsSymbols48Alternate);
|
||||
server.on("/aprs-symbols-48-2.png", HTTP_GET, handleAprsSymbols48Overlay);
|
||||
server.on("/aprs-symbols-24-0.png", HTTP_GET, handleAprsSymbols24Primary);
|
||||
server.on("/aprs-symbols-24-1.png", HTTP_GET, handleAprsSymbols24Alternate);
|
||||
server.on("/aprs-symbols-24-2.png", HTTP_GET, handleAprsSymbols24Overlay);
|
||||
|
||||
OTA_Utils::setup(&server); // Include OTA Updater for WebServer
|
||||
|
||||
|
||||
+3
-3
@@ -29,9 +29,9 @@ files = [
|
||||
'data_embed/leaflet.js',
|
||||
'data_embed/leaflet.css',
|
||||
'data_embed/favicon.png',
|
||||
'data_embed/aprs-symbols-48-0.png',
|
||||
'data_embed/aprs-symbols-48-1.png',
|
||||
'data_embed/aprs-symbols-48-2.png',
|
||||
'data_embed/aprs-symbols-24-0.png',
|
||||
'data_embed/aprs-symbols-24-1.png',
|
||||
'data_embed/aprs-symbols-24-2.png',
|
||||
]
|
||||
|
||||
string_to_find_str = "String"
|
||||
|
||||
Reference in new issue
Block a user