mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-03-28 16:52:33 +01:00
Compare commits
106 Commits
APRS-IS-pa
...
new-json
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f87a89213f | ||
|
|
3810821f45 | ||
|
|
6a3b1c903d | ||
|
|
11c36a91fb | ||
|
|
a97ffe709f | ||
|
|
c80b565730 | ||
|
|
84cbcc30e8 | ||
|
|
11d413cb17 | ||
|
|
19d767e3cb | ||
|
|
803bde1008 | ||
|
|
8ab1f5ec24 | ||
|
|
cfc9474469 | ||
|
|
949807bc14 | ||
|
|
37e3a2f831 | ||
|
|
8bca896e31 | ||
|
|
e241321abc | ||
|
|
d8b658df30 | ||
|
|
9775c601bb | ||
|
|
b0d441a519 | ||
|
|
413318e94b | ||
|
|
ec28dc0978 | ||
|
|
e5fa6574f0 | ||
|
|
8a16be1bea | ||
|
|
891fc906bb | ||
|
|
eb4087073b | ||
|
|
10d1fb4ede | ||
|
|
f18d16a6fb | ||
|
|
1edb333b1d | ||
|
|
ca567e720d | ||
|
|
35760b74f7 | ||
|
|
801641f781 | ||
|
|
447c2d4937 | ||
|
|
1668fc1412 | ||
|
|
1ff5504956 | ||
|
|
e0c6608055 | ||
|
|
d2c9bcb71d | ||
|
|
630de55feb | ||
|
|
b5690a2f37 | ||
|
|
a7ae6c9fd4 | ||
|
|
b448e2fc6b | ||
|
|
c33720a5fb | ||
|
|
e57fad6666 | ||
|
|
2418291ac9 | ||
|
|
796ba35357 | ||
|
|
57873e4181 | ||
|
|
453222d69f | ||
|
|
fbb347fb7f | ||
|
|
50fd831fdb | ||
|
|
3a2c0304d0 | ||
|
|
b24c2b2527 | ||
|
|
db0da96d7f | ||
|
|
bf6a0faa90 | ||
|
|
61cf118a3b | ||
|
|
44719083a6 | ||
|
|
808d740477 | ||
|
|
23c8257c80 | ||
|
|
db4582db13 | ||
|
|
09e06d36e8 | ||
|
|
e6d44c1b7f | ||
|
|
d4fc99466f | ||
|
|
41f09af7b5 | ||
|
|
0eec028c5d | ||
|
|
c48dd15bd6 | ||
|
|
f26ded5b5c | ||
|
|
c887689406 | ||
|
|
775e08a10a | ||
|
|
f9291821d2 | ||
|
|
12d0bb760e | ||
|
|
f020eb7491 | ||
|
|
63f4660ef6 | ||
|
|
efabe9b1f7 | ||
|
|
beae88d557 | ||
|
|
8b4d8c2d1d | ||
|
|
08ae1e322b | ||
|
|
d576be0f2b | ||
|
|
7c9903ac12 | ||
|
|
0d7cff14f5 | ||
|
|
5c89635a23 | ||
|
|
7a35f9e32a | ||
|
|
7695675a7c | ||
|
|
c8c0be636d | ||
|
|
76fe27a0ab | ||
|
|
da80391921 | ||
|
|
d638093dbf | ||
|
|
66a5f03c12 | ||
|
|
ce8cf3a2fe | ||
|
|
4b45b90c88 | ||
|
|
dbe980a081 | ||
|
|
bb3d59a20d | ||
|
|
fe590b41b0 | ||
|
|
3f76005949 | ||
|
|
6d95231b9c | ||
|
|
81692010cf | ||
|
|
50b738d04b | ||
|
|
026d6b2eeb | ||
|
|
fe705519cb | ||
|
|
1fa74b8697 | ||
|
|
a3794085b4 | ||
|
|
0a898a40e6 | ||
|
|
ff8c7581fa | ||
|
|
449a8557d2 | ||
|
|
4419c98920 | ||
|
|
45bf90817b | ||
|
|
ef30a1bf58 | ||
|
|
9a705d3dfa | ||
|
|
63f74396d2 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -19,6 +19,8 @@ jobs:
|
||||
chip: esp32s3
|
||||
- name: heltec-lora32-v2
|
||||
chip: esp32
|
||||
- name: heltec-lora32-v2_915
|
||||
chip: esp32
|
||||
- name: heltec_wifi_lora_32_V3
|
||||
chip: esp32s3
|
||||
- name: heltec_wifi_lora_32_V3_2
|
||||
@@ -71,6 +73,10 @@ jobs:
|
||||
chip: esp32c3
|
||||
- name: heltec_wireless_paper_v1
|
||||
chip: esp32s3
|
||||
- name: heltec_wireless_paper_v1_2
|
||||
chip: esp32s3
|
||||
- name: heltec_vision_master_e290
|
||||
chip: esp32s3
|
||||
- name: OE5HWN_MeshCom
|
||||
chip: esp32
|
||||
- name: WEMOS-LOLIN32-OLED-DIY
|
||||
@@ -92,7 +98,9 @@ jobs:
|
||||
- name: XIAO_ESP32S3_WIO_SX1262
|
||||
chip: esp32s3
|
||||
- name: TROY_LoRa_APRS
|
||||
chip: esp32
|
||||
chip: esp32
|
||||
- name: ESP32_9M2IBR_1W_LoRa_GPS
|
||||
chip: esp32
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
10
README.md
10
README.md
@@ -51,6 +51,14 @@ ____________________________________________________
|
||||
<br />
|
||||
|
||||
# Timeline (Versions):
|
||||
- 2026-02-26 9M2IBR ESP32 1W (400M30S) + GPS board added.
|
||||
- 2026-02-25 Code Improvements: reduced String comparisons and improved logic for faster code execution.
|
||||
- 2026-02-15 Digipeater code/logic improved.
|
||||
- 2026-02-08 Heltec V2 915MHz added.
|
||||
- 2026-02-05 Improved "digiBackupMode" to check "APRS-IS" server connection.
|
||||
- 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-18 TCXO and packet decoding updates.
|
||||
- 2025-12-01 APRSPacketLib updates, AHT20 sensor added, INA219 support added.
|
||||
- 2025-10-15 APRS Bridge for TNC added.
|
||||
@@ -82,7 +90,7 @@ ____________________________________________________
|
||||
- 2024.10.08 New EcoMode for Remote Digipeaters without WiFi/WiFiAP, Screen, Leds (Example: LILYGO LoRa32 uses only 24mA, with WifiAP 150mA). APRS Message/Queries can start/stop this mode too.
|
||||
- 2024.10.06 Cross Frequency Digipeater Rules added.
|
||||
- 2024.09.23 Libraries Update for SDK3
|
||||
- 2024.09.23 Added Enconded Telemetry for Battery (+ External Voltage) in Station GPS Beacon Packet.
|
||||
- 2024.09.23 Added Enconded Telemetry for Battery (+ External Voltage) in Station GPS Beacon Packet.
|
||||
- 2024.08.23 Wemos S2 Mini DIY LoRa added.
|
||||
- 2024.08.19 HELTEC Wireless Paper working (still missing Epaper code).
|
||||
- 2024.08.13 Web Authentication for WebUI. Thanks Mitja S57PNX.
|
||||
|
||||
@@ -23,20 +23,20 @@ build_flags =
|
||||
-D RADIOLIB_EXCLUDE_SSTV=1
|
||||
-I variants/${PIOENV}
|
||||
lib_deps =
|
||||
adafruit/Adafruit Unified Sensor @ 1.1.14
|
||||
adafruit/Adafruit AHTX0 @ 2.0.5
|
||||
adafruit/Adafruit BME280 Library @ 2.2.4
|
||||
adafruit/Adafruit BMP280 Library @ 2.6.8
|
||||
adafruit/Adafruit BME680 Library @ 2.0.4
|
||||
adafruit/Adafruit Unified Sensor @ 1.1.15
|
||||
adafruit/Adafruit AHTX0 @ 2.0.6
|
||||
adafruit/Adafruit BME280 Library @ 2.3.0
|
||||
adafruit/Adafruit BMP280 Library @ 3.0.0
|
||||
adafruit/Adafruit BME680 Library @ 2.0.6
|
||||
adafruit/Adafruit INA219 @ 1.2.3
|
||||
adafruit/Adafruit Si7021 Library @ 1.5.3
|
||||
arduino-libraries/NTPClient @ 3.2.1
|
||||
ayushsharma82/ElegantOTA @ 3.1.5
|
||||
bblanchon/ArduinoJson @ 6.21.3
|
||||
jgromes/RadioLib @ 7.1.0
|
||||
ayushsharma82/ElegantOTA @ 3.1.7
|
||||
bblanchon/ArduinoJson @ 7.4.2
|
||||
jgromes/RadioLib @ 7.6.0
|
||||
knolleary/PubSubClient @ 2.8
|
||||
mathieucarbou/AsyncTCP @ 3.2.5
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.2.3
|
||||
ESP32Async/AsyncTCP @ 3.4.10
|
||||
ESP32Async/ESPAsyncWebServer @ 3.10.0
|
||||
mikalhart/TinyGPSPlus @ 1.0.3
|
||||
richonguzman/APRSPacketLib @ 1.0.4
|
||||
display_libs =
|
||||
@@ -44,4 +44,4 @@ display_libs =
|
||||
adafruit/Adafruit SSD1306 @ 2.5.10
|
||||
usb_flags=
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
@@ -36,7 +36,8 @@
|
||||
"blacklist": "",
|
||||
"digi": {
|
||||
"mode": 0,
|
||||
"ecoMode": 0
|
||||
"ecoMode": 0,
|
||||
"backupDigiMode": false
|
||||
},
|
||||
"lora": {
|
||||
"rxActive": true,
|
||||
@@ -113,7 +114,6 @@
|
||||
},
|
||||
"other": {
|
||||
"rememberStationTime": 30,
|
||||
"backupDigiMode": false,
|
||||
"rebootMode": false,
|
||||
"rebootModeTime": 6,
|
||||
"startupDelay": 0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="auto">
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
@@ -36,8 +36,8 @@
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Backup</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="#" id="backup">Download</a>
|
||||
<a class="dropdown-item" href="#" id="restore">Restore</a>
|
||||
<a class="dropdown-item" href="#" id="backup">Download Conf.</a>
|
||||
<a class="dropdown-item" href="#" id="restore">Restore Conf.</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
@@ -119,7 +119,7 @@
|
||||
</div>
|
||||
<div class="col-lg-9 col-sm-12">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="col-6">
|
||||
<label for="callsign" class="form-label"
|
||||
>Callsign - SSID</label
|
||||
>
|
||||
@@ -133,6 +133,19 @@
|
||||
oninput="this.value = this.value.toUpperCase();"
|
||||
/>
|
||||
</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">
|
||||
<label
|
||||
for="beacon.comment"
|
||||
@@ -158,7 +171,7 @@
|
||||
name="beacon.path"
|
||||
id="beacon.path"
|
||||
class="form-control"
|
||||
placeholder="We prefer WIDE1-1"
|
||||
placeholder="WIDE1-1"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-8 mt-3">
|
||||
@@ -188,10 +201,10 @@
|
||||
name="action.symbol"
|
||||
id="action.symbol"
|
||||
>
|
||||
<option value="L#">Green star with L</option>
|
||||
<option value="L_">Blue circle with L</option>
|
||||
<option value="L&">Black diamond with L</option>
|
||||
<option value="La" selected>Red diamond with L</option>
|
||||
<option value="L#">Green Star with L - Digipeater</option>
|
||||
<option value="L_">Blue Circle with L - Station with Wx Data</option>
|
||||
<option value="L&">Black Diamond with L - Rx (only) iGate</option>
|
||||
<option value="La" selected>Red Diamond with L - Rx+Tx iGate</option>
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
@@ -244,7 +257,7 @@
|
||||
name="personalNote"
|
||||
id="personalNote"
|
||||
class="form-control"
|
||||
placeholder="A couple of words"
|
||||
placeholder="Describe here your Station"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 mt-3">
|
||||
@@ -591,11 +604,11 @@
|
||||
type="number"
|
||||
name="beacon.interval"
|
||||
id="beacon.interval"
|
||||
placeholder="15"
|
||||
class="form-control"
|
||||
required=""
|
||||
value="15"
|
||||
min="10"
|
||||
step="1"
|
||||
min="15"
|
||||
required
|
||||
/>
|
||||
<span class="input-group-text"
|
||||
>minutes
|
||||
@@ -735,6 +748,24 @@
|
||||
<option value="1">Ultra Eco Mode (Sleep till Packet Rx (WiFiAP/WebUI & Display disabled))</option>
|
||||
<option value="2">OFF (Normal Mode - WiFiAP disabled but Serial Output still enabled)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 mt-3">
|
||||
<div class="form-check form-switch">
|
||||
<div class="form-text">
|
||||
If WiFi/server connection is lost in iGate-only mode, the device switches to Digipeater mode (WIDE1-1) and retries connection every 15 minutes.
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="digi.backupDigiMode"
|
||||
id="digi.backupDigiMode"
|
||||
class="form-check-input"
|
||||
/>
|
||||
<label
|
||||
for="digi.backupDigiMode"
|
||||
class="form-label"
|
||||
>Backup Digipeater Mode</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -853,7 +884,9 @@
|
||||
id="lora.rxSpreadingFactor"
|
||||
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="9">SF9</option>
|
||||
<option value="10">SF10</option>
|
||||
@@ -873,7 +906,9 @@
|
||||
id="lora.txSpreadingFactor"
|
||||
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="9">SF9</option>
|
||||
<option value="10">SF10</option>
|
||||
@@ -1818,46 +1853,68 @@
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<label
|
||||
for="wifi.autoAP.password"
|
||||
class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<div class="col-12">
|
||||
<div class="form-check form-switch">
|
||||
<input
|
||||
type="password"
|
||||
name="wifi.autoAP.password"
|
||||
id="wifi.autoAP.password"
|
||||
class="form-control"
|
||||
placeholder="1234567890"
|
||||
required=""
|
||||
type="checkbox"
|
||||
name="wifi.autoAP.enabled"
|
||||
id="wifi.autoAP.enabled"
|
||||
class="form-check-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label
|
||||
for="wifi.autoAP.timeout"
|
||||
class="form-label"
|
||||
>WiFiAP timeout (to search again)</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="number"
|
||||
name="wifi.autoAP.timeout"
|
||||
id="wifi.autoAP.timeout"
|
||||
class="form-control"
|
||||
placeholder="10"
|
||||
required=""
|
||||
step="1"
|
||||
min="0"
|
||||
/>
|
||||
<span class="input-group-text"
|
||||
>minutes</span
|
||||
<label
|
||||
for="wifi.autoAP.enabled"
|
||||
class="form-label"
|
||||
>Enable Auto AP</label
|
||||
>
|
||||
<div class="form-text">
|
||||
Set to <strong>0</strong> if you don't
|
||||
want WiFi AP to stop.
|
||||
Create WiFi AP when no network is available
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="wifi-autoap-config" style="{{wifi.autoAP.enabled ? '' : 'display:none'}}">
|
||||
<div class="row mt-3">
|
||||
<div class="col-6">
|
||||
<label
|
||||
for="wifi.autoAP.password"
|
||||
class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="password"
|
||||
name="wifi.autoAP.password"
|
||||
id="wifi.autoAP.password"
|
||||
class="form-control"
|
||||
placeholder="1234567890"
|
||||
required=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label
|
||||
for="wifi.autoAP.timeout"
|
||||
class="form-label"
|
||||
>WiFiAP timeout (to search again)</label
|
||||
>
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="number"
|
||||
name="wifi.autoAP.timeout"
|
||||
id="wifi.autoAP.timeout"
|
||||
class="form-control"
|
||||
placeholder="10"
|
||||
required=""
|
||||
step="1"
|
||||
min="0"
|
||||
/>
|
||||
<span class="input-group-text"
|
||||
>minutes</span
|
||||
>
|
||||
<div class="form-text">
|
||||
Set to <strong>0</strong> if you don't
|
||||
want WiFi AP to stop.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2110,52 +2167,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="row my-5 d-flex align-items-top">
|
||||
<div class="col-lg-3 col-sm-12">
|
||||
<h5>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
fill="currentColor"
|
||||
class="bi bi-heart-pulse-fill"
|
||||
viewBox="0 0 16 16"
|
||||
>
|
||||
<path
|
||||
d="M1.475 9C2.702 10.84 4.779 12.871 8 15c3.221-2.129 5.298-4.16 6.525-6H12a.5.5 0 0 1-.464-.314l-1.457-3.642-1.598 5.593a.5.5 0 0 1-.945.049L5.889 6.568l-1.473 2.21A.5.5 0 0 1 4 9z"
|
||||
/>
|
||||
<path
|
||||
d="M.88 8C-2.427 1.68 4.41-2 7.823 1.143q.09.083.176.171a3 3 0 0 1 .176-.17C11.59-2 18.426 1.68 15.12 8h-2.783l-1.874-4.686a.5.5 0 0 0-.945.049L7.921 8.956 6.464 5.314a.5.5 0 0 0-.88-.091L3.732 8z"
|
||||
/>
|
||||
</svg>
|
||||
Experimental
|
||||
</h5>
|
||||
<small>You can test new features. <u>Use at your own risk!</u></small>
|
||||
</div>
|
||||
<div class="col-lg-9 col-sm-12">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="form-check form-switch">
|
||||
<div class="form-text">
|
||||
When "only" iGate Mode loses WiFi, it will change into a Digipeater Mode and after 15 min check if WiFi available and return to "only" iGate Mode.
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
name="other.backupDigiMode"
|
||||
id="other.backupDigiMode"
|
||||
class="form-check-input"
|
||||
/>
|
||||
<label
|
||||
for="other.backupDigiMode"
|
||||
class="form-label"
|
||||
>Backup Digipeater Mode</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer
|
||||
@@ -2210,7 +2221,7 @@
|
||||
<a
|
||||
href="https://cd3eap.aguayoki.cl/"
|
||||
target="_blank"
|
||||
>CD3EAP</a
|
||||
>CA3EAP</a
|
||||
></b
|
||||
>: Settings Page.
|
||||
</p>
|
||||
|
||||
@@ -54,6 +54,7 @@ function loadSettings(settings) {
|
||||
currentSettings = settings;
|
||||
// General
|
||||
document.getElementById("callsign").value = settings.callsign;
|
||||
document.getElementById("tacticalCallsign").value = settings.tacticalCallsign;
|
||||
document.getElementById("beacon.comment").value = settings.beacon.comment;
|
||||
document.getElementById("beacon.path").value = settings.beacon.path;
|
||||
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
|
||||
@@ -139,6 +140,7 @@ function loadSettings(settings) {
|
||||
// Digi
|
||||
document.getElementById("digi.mode").value = settings.digi.mode;
|
||||
document.getElementById("digi.ecoMode").value = settings.digi.ecoMode;
|
||||
document.getElementById("digi.backupDigiMode").checked = settings.digi.backupDigiMode;
|
||||
|
||||
// LoRa
|
||||
document.getElementById("lora.rxActive").checked = settings.lora.rxActive;
|
||||
@@ -235,8 +237,10 @@ function loadSettings(settings) {
|
||||
RebootModeTime.disabled = !RebootModeCheckbox.check;
|
||||
|
||||
// WiFi Auto AP
|
||||
document.getElementById("wifi.autoAP.enabled").checked = settings.wifi.autoAP.enabled;
|
||||
document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password;
|
||||
document.getElementById("wifi.autoAP.timeout").value = settings.wifi.autoAP.timeout;
|
||||
toggleWiFiAutoAPFields();
|
||||
|
||||
// OTA
|
||||
document.getElementById("ota.username").value = settings.ota.username;
|
||||
@@ -258,9 +262,6 @@ function loadSettings(settings) {
|
||||
document.getElementById("ntp.server").value = settings.ntp.server;
|
||||
document.getElementById("ntp.gmtCorrection").value = settings.ntp.gmtCorrection;
|
||||
|
||||
// Experimental
|
||||
document.getElementById("other.backupDigiMode").checked = settings.other.backupDigiMode;
|
||||
|
||||
updateImage();
|
||||
}
|
||||
|
||||
@@ -433,6 +434,18 @@ WebadminCheckbox.addEventListener("change", function () {
|
||||
WebadminPassword.disabled = !this.checked;
|
||||
});
|
||||
|
||||
// WiFi Auto AP Switches
|
||||
const WiFiAutoAPCheckbox = document.querySelector('input[name="wifi.autoAP.enabled"]');
|
||||
WiFiAutoAPCheckbox.addEventListener("change", function () {
|
||||
toggleWiFiAutoAPFields();
|
||||
});
|
||||
|
||||
function toggleWiFiAutoAPFields() {
|
||||
const isEnabled = WiFiAutoAPCheckbox.checked;
|
||||
const autoAPConfig = document.getElementById('wifi-autoap-config');
|
||||
if (autoAPConfig) autoAPConfig.style.display = isEnabled ? 'block' : 'none';
|
||||
}
|
||||
|
||||
|
||||
document.querySelector(".new button").addEventListener("click", function () {
|
||||
const networksContainer = document.querySelector(".list-networks");
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
|
||||
class WiFi_Auto_AP {
|
||||
public:
|
||||
bool enabled; // Enable Auto AP
|
||||
String password;
|
||||
int timeout;
|
||||
};
|
||||
@@ -44,7 +45,7 @@ public:
|
||||
int interval;
|
||||
String overlay;
|
||||
String symbol;
|
||||
String path;
|
||||
String path;
|
||||
bool sendViaAPRSIS;
|
||||
bool sendViaRF;
|
||||
int beaconFreq;
|
||||
@@ -68,7 +69,8 @@ public:
|
||||
class DIGI {
|
||||
public:
|
||||
int mode;
|
||||
int ecoMode; // 0 = Not Active | 1 = Ultra EcoMode | 2 = Not Active (WiFi OFF, Serial ON)
|
||||
int ecoMode; // 0 = Not Active | 1 = Ultra EcoMode | 2 = Not Active (WiFi OFF, Serial ON)
|
||||
bool backupDigiMode;
|
||||
};
|
||||
|
||||
class LoraModule {
|
||||
@@ -77,7 +79,7 @@ public:
|
||||
long rxFreq;
|
||||
int rxSpreadingFactor;
|
||||
int rxCodingRate4;
|
||||
long rxSignalBandwidth;
|
||||
long rxSignalBandwidth;
|
||||
bool txActive;
|
||||
long txFreq;
|
||||
int txSpreadingFactor;
|
||||
@@ -170,8 +172,8 @@ public:
|
||||
class Configuration {
|
||||
public:
|
||||
String callsign;
|
||||
String tacticalCallsign;
|
||||
int rememberStationTime;
|
||||
bool backupDigiMode;
|
||||
bool rebootMode;
|
||||
int rebootModeTime;
|
||||
int startupDelay;
|
||||
@@ -187,20 +189,20 @@ public:
|
||||
BATTERY battery;
|
||||
WXSENSOR wxsensor;
|
||||
SYSLOG syslog;
|
||||
TNC tnc;
|
||||
TNC tnc;
|
||||
OTA ota;
|
||||
WEBADMIN webadmin;
|
||||
NTP ntp;
|
||||
NTP ntp;
|
||||
REMOTE_MANAGEMENT remoteManagement;
|
||||
MQTT mqtt;
|
||||
|
||||
void setup();
|
||||
void setDefaultValues();
|
||||
bool writeFile();
|
||||
Configuration();
|
||||
|
||||
private:
|
||||
bool readFile();
|
||||
String _filePath;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
|
||||
|
||||
void displaySetup();
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
82
include/network_manager.h
Normal file
82
include/network_manager.h
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include <ETH.h>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Class for managing network connections
|
||||
*/
|
||||
class NetworkManager
|
||||
{
|
||||
private:
|
||||
class WiFiNetwork {
|
||||
public:
|
||||
String ssid;
|
||||
String psk;
|
||||
};
|
||||
|
||||
bool _wifiAPmode = false;
|
||||
bool _wifiSTAmode = false;
|
||||
bool _ethernetMode = false;
|
||||
bool _ethernetConnected = false;
|
||||
unsigned long _apStartup = 0;
|
||||
unsigned long _apTimeout = 0;
|
||||
|
||||
String _hostName = "";
|
||||
std::vector<WiFiNetwork> _wifiNetworks;
|
||||
|
||||
int _findWiFiNetworkIndex(const String& ssid) const;
|
||||
bool _connectWiFi(const WiFiNetwork& network);
|
||||
void _processAPTimeout();
|
||||
void _onNetworkEvent(arduino_event_id_t event, arduino_event_info_t /*info*/);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
NetworkManager();
|
||||
|
||||
// Destructor
|
||||
~NetworkManager();
|
||||
|
||||
// Initialize network module
|
||||
bool setup();
|
||||
void loop();
|
||||
|
||||
void setHostName(const String& hostName);
|
||||
|
||||
// WiFi methods
|
||||
bool setupAP(String apName, String apPsk = "");
|
||||
bool disableAP();
|
||||
void setAPTimeout(unsigned long timeout);
|
||||
void addWiFiNetwork(const String& ssid, const String& psk = "");
|
||||
void clearWiFiNetworks();
|
||||
bool hasWiFiNetworks() const;
|
||||
size_t getWiFiNetworkCount() const;
|
||||
bool connectWiFi();
|
||||
bool connectWiFi(const String& ssid, const String& psk = "");
|
||||
bool disconnectWiFi();
|
||||
String getWiFiSSID() const;
|
||||
String getWiFiAPSSID() const;
|
||||
IPAddress getWiFiIP() const;
|
||||
IPAddress getWiFiAPIP() const;
|
||||
wifi_mode_t getWiFiMode() const;
|
||||
uint8_t* getWiFimacAddress(uint8_t* mac);
|
||||
String getWiFimacAddress(void) const;
|
||||
|
||||
// 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;
|
||||
|
||||
// Check if any network is available
|
||||
bool isConnected() const;
|
||||
|
||||
// Check if specific network is connected
|
||||
bool isWiFiConnected() const;
|
||||
bool isEthernetConnected() const;
|
||||
bool isModemConnected() const;
|
||||
|
||||
bool isWifiAPActive() const;
|
||||
};
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
namespace NTP_Utils {
|
||||
|
||||
void setup();
|
||||
bool setup();
|
||||
void update();
|
||||
String getFormatedTime();
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@ namespace POWER_Utils {
|
||||
void vext_ctrl_OFF();
|
||||
#endif
|
||||
|
||||
#ifdef ADC_CTRL
|
||||
#ifdef ADC_CTRL_PIN
|
||||
void adc_ctrl_ON();
|
||||
void adc_ctrl_OFF();
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -21,8 +21,9 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
namespace SLEEP_Utils {
|
||||
|
||||
|
||||
void setup();
|
||||
void checkWakeUpFlag();
|
||||
void startSleeping();
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -37,8 +37,7 @@ namespace STATION_Utils {
|
||||
void deleteNotHeard();
|
||||
void updateLastHeard(const String& station);
|
||||
bool wasHeard(const String& station);
|
||||
void clean25SegBuffer();
|
||||
bool check25SegBuffer(const String& station, const String& textMessage);
|
||||
bool isIn25SegHashBuffer(const String& station, const String& textMessage);
|
||||
void processOutputPacketBufferUltraEcoMode();
|
||||
void processOutputPacketBuffer();
|
||||
void addToOutputPacketBuffer(const String& packet, bool flag = false);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -27,7 +27,8 @@ namespace TELEMETRY_Utils {
|
||||
void sendEquationsUnitsParameters();
|
||||
String generateEncodedTelemetryBytes(float value, bool counterBytes, byte telemetryType);
|
||||
String generateEncodedTelemetry();
|
||||
|
||||
void checkEUPInterval();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ namespace Utils {
|
||||
void checkRebootMode();
|
||||
void checkRebootTime();
|
||||
void checkSleepByLowBatteryVoltage(uint8_t mode);
|
||||
bool checkValidCallsign(const String& callsign);
|
||||
bool callsignIsValid(const String& callsign);
|
||||
void startupDelay();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -27,7 +27,6 @@ namespace WIFI_Utils {
|
||||
void checkWiFi();
|
||||
void startAutoAP();
|
||||
void startWiFi();
|
||||
void checkAutoAPTimeout();
|
||||
void setup();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -20,7 +20,7 @@
|
||||
#define WX_UTILS_H_
|
||||
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_AHTX0.h>
|
||||
#include <Adafruit_AHTX0.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <Adafruit_BME680.h>
|
||||
|
||||
@@ -16,7 +16,7 @@ extra_configs =
|
||||
variants/*/platformio.ini
|
||||
|
||||
[env]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform = espressif32 @ 6.12.0
|
||||
board_build.partitions = min_spiffs.csv
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
#ifdef HAS_A7670
|
||||
#define TINY_GSM_MODEM_SIM7600 //The AT instruction of A7670 is compatible with SIM7600
|
||||
#define TINY_GSM_MODEM_SIM7600 //The AT instruction of A7670 is compatible with SIM7600
|
||||
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
|
||||
#define SerialAT Serial1
|
||||
#include <TinyGsmClient.h>
|
||||
@@ -115,6 +115,8 @@
|
||||
if (SerialAT.available()) {
|
||||
String response = SerialAT.readString();
|
||||
//Serial.println(response); // DEBUG of Modem AT message
|
||||
int responseOKIndex = response.indexOf("OK");
|
||||
int callsignIndex = ATMessage.indexOf(Config.callsign);
|
||||
if(response.indexOf("verified") >= 0) {
|
||||
Serial.println("Logged! (User Validated)\n");
|
||||
displayShow(firstLine, "Connecting APRS-IS...", "---> Logged!", " ", 1000);
|
||||
@@ -122,7 +124,7 @@
|
||||
validAT = true;
|
||||
i = 1;
|
||||
delayATMessage = 0;
|
||||
} else if (ATMessage == "AT+NETOPEN" && response.indexOf("OK") >= 0) {
|
||||
} else if (ATMessage == "AT+NETOPEN" && responseOKIndex >= 0) {
|
||||
Serial.println("Port Open!");
|
||||
displayShow(firstLine, "Opening Port...", "---> Port Open", " ", 0);
|
||||
validAT = true;
|
||||
@@ -145,14 +147,14 @@
|
||||
validAT = true;
|
||||
i = 1;
|
||||
delayATMessage = 0;
|
||||
} else if (ATMessage.indexOf(Config.callsign) >= 3 && !modemLoggedToAPRSIS && response.indexOf("OK") >= 0 && !stationBeacon) { // login info
|
||||
} else if (callsignIndex >= 3 && !modemLoggedToAPRSIS && responseOKIndex >= 0 && !stationBeacon) { // login info
|
||||
validAT = true;
|
||||
delayATMessage = 0;
|
||||
} else if (ATMessage.indexOf(Config.callsign) == 0 && !beaconSent && response.indexOf("OK") >= 0 && !stationBeacon) { // self beacon or querys
|
||||
} else if (callsignIndex == 0 && !beaconSent && responseOKIndex >= 0 && !stationBeacon) { // self beacon or querys
|
||||
validAT = true;
|
||||
i = 1;
|
||||
delayATMessage = 0;
|
||||
} else if (stationBeacon && response.indexOf("OK") >= 0) { //upload others beacons
|
||||
} else if (stationBeacon && responseOKIndex >= 0) { //upload others beacons
|
||||
validAT = true;
|
||||
i = 1;
|
||||
delayATMessage = 0;
|
||||
@@ -200,7 +202,7 @@
|
||||
if (beaconBytesSent) {
|
||||
Serial.print(".");
|
||||
beaconSent = checkATResponse(packet);
|
||||
}
|
||||
}
|
||||
if (!beaconSent) {
|
||||
Serial.println("------------------------------------> UPLOAD FAILED!!!");
|
||||
} else {
|
||||
@@ -221,5 +223,5 @@
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -24,7 +24,7 @@
|
||||
██║ ██║ ██║██╔══██╗██╔══██║ ██╔══██║██╔═══╝ ██╔══██╗╚════██║
|
||||
███████╗╚██████╔╝██║ ██║██║ ██║ ██║ ██║██║ ██║ ██║███████║
|
||||
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝
|
||||
|
||||
|
||||
██╗ ██████╗ █████╗ ████████╗███████╗
|
||||
██║██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
|
||||
██║██║ ███╗███████║ ██║ █████╗
|
||||
@@ -41,9 +41,10 @@ ___________________________________________________________________*/
|
||||
#include <ElegantOTA.h>
|
||||
#include <TinyGPS++.h>
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <vector>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "aprs_is_utils.h"
|
||||
#include "station_utils.h"
|
||||
#include "battery_utils.h"
|
||||
@@ -67,8 +68,8 @@ ___________________________________________________________________*/
|
||||
#endif
|
||||
|
||||
|
||||
String versionDate = "2025-12-22";
|
||||
String versionNumber = "3.1.6.1";
|
||||
String versionDate = "2026-03-11";
|
||||
String versionNumber = "3.2.107";
|
||||
Configuration Config;
|
||||
WiFiClient aprsIsClient;
|
||||
WiFiClient mqttClient;
|
||||
@@ -79,14 +80,12 @@ WiFiClient mqttClient;
|
||||
bool gpsInfoToggle = false;
|
||||
#endif
|
||||
|
||||
uint8_t myWiFiAPIndex = 0;
|
||||
int myWiFiAPSize = Config.wifiAPs.size();
|
||||
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
|
||||
NetworkManager *networkManager;
|
||||
|
||||
bool isUpdatingOTA = false;
|
||||
uint32_t lastBatteryCheck = 0;
|
||||
|
||||
bool backUpDigiMode = false;
|
||||
bool backupDigiMode = false;
|
||||
bool modemLoggedToAPRSIS = false;
|
||||
|
||||
#ifdef HAS_EPAPER
|
||||
@@ -101,6 +100,13 @@ String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seven
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Config.setup();
|
||||
networkManager = new NetworkManager();
|
||||
networkManager->setup();
|
||||
if (Config.wifiAutoAP.enabled) {
|
||||
networkManager->setAPTimeout(Config.wifiAutoAP.timeout * 60 * 1000); // Convert minutes to milliseconds
|
||||
}
|
||||
networkManager->setHostName("iGATE-" + Config.callsign);
|
||||
POWER_Utils::setup();
|
||||
Utils::setupDisplay();
|
||||
LoRa_Utils::setup();
|
||||
@@ -132,13 +138,13 @@ void loop() {
|
||||
Utils::checkSleepByLowBatteryVoltage(1);
|
||||
SLEEP_Utils::startSleeping();
|
||||
} else {
|
||||
WIFI_Utils::checkAutoAPTimeout();
|
||||
networkManager->loop();
|
||||
|
||||
if (isUpdatingOTA) {
|
||||
ElegantOTA.loop();
|
||||
return; // Don't process IGate and Digi during OTA update
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_GPS
|
||||
if (Config.beacon.gpsActive) {
|
||||
if (millis() - gpsSatelliteTime > 5000) {
|
||||
@@ -161,11 +167,14 @@ void loop() {
|
||||
#endif
|
||||
|
||||
#ifdef HAS_A7670
|
||||
// TODO: Make this part of Network manager, and use ESP-IDF network stack instead manual AT commands
|
||||
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
|
||||
#else
|
||||
WIFI_Utils::checkWiFi();
|
||||
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) APRS_IS_Utils::connect();
|
||||
if (Config.mqtt.active && (WiFi.status() == WL_CONNECTED) && !mqttClient.connected()) MQTT_Utils::connect();
|
||||
if (networkManager->isConnected()) {
|
||||
if (Config.aprs_is.active && !aprsIsClient.connected()) APRS_IS_Utils::connect();
|
||||
if (Config.mqtt.active && !mqttClient.connected()) MQTT_Utils::connect();
|
||||
}
|
||||
#endif
|
||||
|
||||
NTP_Utils::update();
|
||||
@@ -174,7 +183,7 @@ void loop() {
|
||||
|
||||
Utils::checkDisplayInterval();
|
||||
Utils::checkBeaconInterval();
|
||||
|
||||
|
||||
APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func?
|
||||
|
||||
String packet = "";
|
||||
@@ -187,8 +196,7 @@ void loop() {
|
||||
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
|
||||
}
|
||||
|
||||
if (Config.loramodule.txActive && (Config.digi.mode == 2 || Config.digi.mode == 3 || backUpDigiMode)) { // If Digi enabled
|
||||
STATION_Utils::clean25SegBuffer();
|
||||
if (Config.loramodule.txActive && (Config.digi.mode == 2 || Config.digi.mode == 3 || backupDigiMode)) { // If Digi enabled
|
||||
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
|
||||
}
|
||||
|
||||
@@ -217,4 +225,4 @@ void loop() {
|
||||
Utils::checkRebootTime();
|
||||
Utils::checkSleepByLowBatteryVoltage(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "aprs_is_utils.h"
|
||||
#include "station_utils.h"
|
||||
#include "board_pinout.h"
|
||||
@@ -32,6 +33,7 @@
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
extern WiFiClient aprsIsClient;
|
||||
extern uint32_t lastScreenOn;
|
||||
extern String firstLine;
|
||||
@@ -42,11 +44,13 @@ extern String fifthLine;
|
||||
extern String sixthLine;
|
||||
extern String seventhLine;
|
||||
extern bool modemLoggedToAPRSIS;
|
||||
extern bool backUpDigiMode;
|
||||
extern bool backupDigiMode;
|
||||
extern String versionNumber;
|
||||
|
||||
uint32_t lastRxTime = millis();
|
||||
bool passcodeValid = false;
|
||||
uint32_t lastServerCheck = 0;
|
||||
|
||||
|
||||
#ifdef HAS_A7670
|
||||
extern bool stationBeacon;
|
||||
@@ -91,10 +95,10 @@ namespace APRS_IS_Utils {
|
||||
|
||||
void checkStatus() {
|
||||
String wifiState, aprsisState;
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (networkManager->isWiFiConnected()) {
|
||||
wifiState = "OK";
|
||||
} else {
|
||||
if (backUpDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
|
||||
if (backupDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
|
||||
wifiState = "--";
|
||||
} else {
|
||||
wifiState = "AP";
|
||||
@@ -133,30 +137,30 @@ namespace APRS_IS_Utils {
|
||||
}
|
||||
|
||||
String checkForStartingBytes(const String& packet) {
|
||||
if (packet.indexOf("\x3c\xff\x01") != -1) {
|
||||
return packet.substring(0, packet.indexOf("\x3c\xff\x01"));
|
||||
} else {
|
||||
return packet;
|
||||
}
|
||||
int index = packet.indexOf("\x3c\xff\x01");
|
||||
return (index != -1) ? packet.substring(0, index) : packet;
|
||||
}
|
||||
|
||||
String buildPacketToUpload(const String& packet) {
|
||||
String packetToUpload = packet.substring(3, packet.indexOf(":"));
|
||||
int colonIndex = packet.indexOf(":");
|
||||
String packetToUpload = packet.substring(3, colonIndex);
|
||||
if (Config.aprs_is.active && passcodeValid && Config.aprs_is.messagesToRF) {
|
||||
packetToUpload += ",qAR,";
|
||||
} else {
|
||||
packetToUpload += ",qAO,";
|
||||
}
|
||||
packetToUpload += Config.callsign;
|
||||
packetToUpload += checkForStartingBytes(packet.substring(packet.indexOf(":")));
|
||||
packetToUpload += checkForStartingBytes(packet.substring(colonIndex));
|
||||
return packetToUpload;
|
||||
}
|
||||
|
||||
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty) {
|
||||
String receivedMessage;
|
||||
if (packet.indexOf("{") > 0) { // ack?
|
||||
int leftCurlyBraceIndex = packet.indexOf("{");
|
||||
int colonIndex = packet.indexOf(":");
|
||||
if (leftCurlyBraceIndex > 0) { // ack?
|
||||
String ackMessage = "ack";
|
||||
ackMessage.concat(packet.substring(packet.indexOf("{") + 1));
|
||||
ackMessage.concat(packet.substring(leftCurlyBraceIndex + 1));
|
||||
ackMessage.trim();
|
||||
//Serial.println(ackMessage);
|
||||
|
||||
@@ -178,9 +182,9 @@ namespace APRS_IS_Utils {
|
||||
addToBuffer += ":";
|
||||
addToBuffer += ackMessage;
|
||||
STATION_Utils::addToOutputPacketBuffer(addToBuffer);
|
||||
receivedMessage = packet.substring(packet.indexOf(":") + 1, packet.indexOf("{"));
|
||||
receivedMessage = packet.substring(colonIndex + 1, leftCurlyBraceIndex);
|
||||
} else {
|
||||
receivedMessage = packet.substring(packet.indexOf(":") + 1);
|
||||
receivedMessage = packet.substring(colonIndex + 1);
|
||||
}
|
||||
if (receivedMessage.indexOf("?") == 0) {
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
@@ -202,32 +206,33 @@ namespace APRS_IS_Utils {
|
||||
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::checkValidCallsign(Sender)) {
|
||||
if (Sender != Config.callsign && Utils::callsignIsValid(Sender)) {
|
||||
STATION_Utils::updateLastHeard(Sender);
|
||||
Utils::typeOfPacket(packet.substring(3), 0); // LoRa-APRS
|
||||
const String& AddresseeAndMessage = packet.substring(packet.indexOf("::") + 2);
|
||||
int doubleColonIndex = packet.indexOf("::");
|
||||
const String& AddresseeAndMessage = packet.substring(doubleColonIndex + 2);
|
||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||
Addressee.trim();
|
||||
bool queryMessage = false;
|
||||
if (packet.indexOf("::") > 10 && Addressee == Config.callsign) { // its a message for me!
|
||||
if (doubleColonIndex > 10 && Addressee == Config.callsign) { // its a message for me!
|
||||
queryMessage = processReceivedLoRaMessage(Sender, checkForStartingBytes(AddresseeAndMessage), false);
|
||||
}
|
||||
if (!queryMessage) {
|
||||
const String& aprsPacket = buildPacketToUpload(packet);
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
}
|
||||
lastScreenOn = millis();
|
||||
#ifdef HAS_A7670
|
||||
stationBeacon = true;
|
||||
A7670_Utils::uploadToAPRSIS(aprsPacket);
|
||||
stationBeacon = false;
|
||||
#else
|
||||
upload(aprsPacket);
|
||||
#endif
|
||||
Utils::println("---> Uploaded to APRS-IS");
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
if (queryMessage) return;
|
||||
|
||||
const String& aprsPacket = buildPacketToUpload(packet);
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
}
|
||||
lastScreenOn = millis();
|
||||
#ifdef HAS_A7670
|
||||
stationBeacon = true;
|
||||
A7670_Utils::uploadToAPRSIS(aprsPacket);
|
||||
stationBeacon = false;
|
||||
#else
|
||||
upload(aprsPacket);
|
||||
#endif
|
||||
Utils::println("---> Uploaded to APRS-IS");
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,26 +248,30 @@ namespace APRS_IS_Utils {
|
||||
outputPacket.concat(",TCPIP,");
|
||||
outputPacket.concat(Config.callsign);
|
||||
outputPacket.concat("*");
|
||||
int colonEqualIndex = packet.indexOf(":=");
|
||||
int doubleColonIndex = packet.indexOf("::");
|
||||
int colonInvAccentIndex = packet.indexOf(":`");
|
||||
|
||||
switch (packetType) {
|
||||
case 0: // gps
|
||||
if (packet.indexOf(":=") > 0) {
|
||||
outputPacket += packet.substring(packet.indexOf(":="));
|
||||
if (colonEqualIndex > 0) {
|
||||
outputPacket += packet.substring(colonEqualIndex);
|
||||
} else {
|
||||
outputPacket += packet.substring(packet.indexOf(":!"));
|
||||
}
|
||||
break;
|
||||
case 1: // messages
|
||||
outputPacket += packet.substring(packet.indexOf("::"));
|
||||
outputPacket += packet.substring(doubleColonIndex);
|
||||
break;
|
||||
case 2: // status
|
||||
outputPacket += packet.substring(packet.indexOf(":>"));
|
||||
break;
|
||||
case 3: // telemetry
|
||||
outputPacket += packet.substring(packet.indexOf("::"));
|
||||
outputPacket += packet.substring(doubleColonIndex);
|
||||
break;
|
||||
case 4: // mic-e
|
||||
if (packet.indexOf(":`") > 0) {
|
||||
outputPacket += packet.substring(packet.indexOf(":`"));
|
||||
if (colonInvAccentIndex > 0) {
|
||||
outputPacket += packet.substring(colonInvAccentIndex);
|
||||
} else {
|
||||
outputPacket += packet.substring(packet.indexOf(":'"));
|
||||
}
|
||||
@@ -274,7 +283,31 @@ namespace APRS_IS_Utils {
|
||||
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) {
|
||||
uint32_t currentTime = millis();
|
||||
if (!passcodeValid && packet.indexOf(Config.callsign) != -1) {
|
||||
if (packet.indexOf("unverified") != -1 ) {
|
||||
Serial.println("\n****APRS PASSCODE NOT VALID****\n");
|
||||
@@ -282,93 +315,82 @@ namespace APRS_IS_Utils {
|
||||
aprsIsClient.stop();
|
||||
Config.aprs_is.active = false;
|
||||
} else if (packet.indexOf("verified") != -1 ) {
|
||||
if (Config.digi.backupDigiMode) lastServerCheck = currentTime;
|
||||
passcodeValid = true;
|
||||
}
|
||||
}
|
||||
if (passcodeValid && !packet.startsWith("#")) {
|
||||
if (Config.aprs_is.messagesToRF && packet.indexOf("::") > 0) {
|
||||
String Sender = packet.substring(0, packet.indexOf(">"));
|
||||
const String& AddresseeAndMessage = packet.substring(packet.indexOf("::") + 2);
|
||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||
Addressee.trim();
|
||||
if (Addressee == Config.callsign) { // its for me!
|
||||
String receivedMessage;
|
||||
if (AddresseeAndMessage.indexOf("{") > 0) { // ack?
|
||||
String ackMessage = "ack";
|
||||
ackMessage += AddresseeAndMessage.substring(AddresseeAndMessage.indexOf("{") + 1);
|
||||
ackMessage.trim();
|
||||
delay(4000);
|
||||
for (int i = Sender.length(); i < 9; i++) {
|
||||
Sender += ' ';
|
||||
if (passcodeValid) {
|
||||
if (packet.startsWith("#")) {
|
||||
if (Config.digi.backupDigiMode) lastServerCheck = currentTime;
|
||||
} else {
|
||||
int doubleColonIndex = packet.indexOf("::");
|
||||
if (Config.aprs_is.messagesToRF && doubleColonIndex > 0) {
|
||||
String Sender = packet.substring(0, packet.indexOf(">"));
|
||||
const String& AddresseeAndMessage = packet.substring(doubleColonIndex + 2);
|
||||
int colonIndex = AddresseeAndMessage.indexOf(":");
|
||||
String Addressee = AddresseeAndMessage.substring(0, colonIndex);
|
||||
Addressee.trim();
|
||||
if (Addressee == Config.callsign) { // its for me!
|
||||
String receivedMessage;
|
||||
int curlyBraceIndex = AddresseeAndMessage.indexOf("{");
|
||||
if (curlyBraceIndex > 0) { // ack?
|
||||
processAckMessage(Sender, AddresseeAndMessage);
|
||||
receivedMessage = AddresseeAndMessage.substring(colonIndex + 1, curlyBraceIndex);
|
||||
} else {
|
||||
receivedMessage = AddresseeAndMessage.substring(colonIndex + 1);
|
||||
}
|
||||
|
||||
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("{"));
|
||||
} else {
|
||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1);
|
||||
}
|
||||
if (receivedMessage.indexOf("?") == 0) {
|
||||
Utils::println("Rx Query (APRS-IS) : " + packet);
|
||||
Sender.trim();
|
||||
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false);
|
||||
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
if (receivedMessage.indexOf("?") == 0) {
|
||||
Utils::println("Rx Query (APRS-IS) : " + packet);
|
||||
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false);
|
||||
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||
displayToggle(true);
|
||||
}
|
||||
lastScreenOn = currentTime;
|
||||
#ifdef HAS_A7670
|
||||
A7670_Utils::uploadToAPRSIS(queryAnswer);
|
||||
#else
|
||||
upload(queryAnswer);
|
||||
#endif
|
||||
SYSLOG_Utils::log(2, queryAnswer, 0, 0.0, 0); // APRSIS TX
|
||||
fifthLine = "APRS-IS ----> APRS-IS";
|
||||
sixthLine = Config.callsign;
|
||||
for (int j = sixthLine.length();j < 9;j++) {
|
||||
sixthLine += " ";
|
||||
}
|
||||
sixthLine += "> ";
|
||||
sixthLine += Sender;
|
||||
seventhLine = "QUERY = ";
|
||||
seventhLine += receivedMessage;
|
||||
}
|
||||
lastScreenOn = millis();
|
||||
delay(500);
|
||||
#ifdef HAS_A7670
|
||||
A7670_Utils::uploadToAPRSIS(queryAnswer);
|
||||
#else
|
||||
upload(queryAnswer);
|
||||
#endif
|
||||
SYSLOG_Utils::log(2, queryAnswer, 0, 0.0, 0); // APRSIS TX
|
||||
fifthLine = "APRS-IS ----> APRS-IS";
|
||||
sixthLine = Config.callsign;
|
||||
for (int j = sixthLine.length();j < 9;j++) {
|
||||
sixthLine += " ";
|
||||
}
|
||||
sixthLine += "> ";
|
||||
sixthLine += Sender;
|
||||
seventhLine = "QUERY = ";
|
||||
seventhLine += receivedMessage;
|
||||
}
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
} else {
|
||||
Utils::print("Rx Message (APRS-IS): " + packet);
|
||||
if (STATION_Utils::wasHeard(Addressee) && packet.indexOf("EQNS.") == -1 && packet.indexOf("UNIT.") == -1 && packet.indexOf("PARM.") == -1) {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 1));
|
||||
displayToggle(true);
|
||||
lastScreenOn = millis();
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
} else {
|
||||
Utils::print("Rx Message (APRS-IS): " + packet);
|
||||
if (STATION_Utils::wasHeard(Addressee) && packet.indexOf("EQNS.") == -1 && packet.indexOf("UNIT.") == -1 && packet.indexOf("PARM.") == -1) {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 1));
|
||||
displayToggle(true);
|
||||
lastScreenOn = currentTime;
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||
}
|
||||
}
|
||||
} else if (Config.aprs_is.objectsToRF && packet.indexOf(":;") > 0) {
|
||||
Utils::print("Rx Object (APRS-IS) : " + packet);
|
||||
if (STATION_Utils::checkObjectTime(packet)) {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 5));
|
||||
displayToggle(true);
|
||||
lastScreenOn = currentTime;
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.println(" ---> Rejected (Time): No Tx");
|
||||
}
|
||||
}
|
||||
} else if (Config.aprs_is.objectsToRF && packet.indexOf(":;") > 0) {
|
||||
Utils::print("Rx Object (APRS-IS) : " + packet);
|
||||
if (STATION_Utils::checkObjectTime(packet)) {
|
||||
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 5));
|
||||
displayToggle(true);
|
||||
lastScreenOn = millis();
|
||||
Utils::typeOfPacket(packet, 1); // APRS-LoRa
|
||||
Serial.println();
|
||||
} else {
|
||||
Serial.println(" ---> Rejected (Time): No Tx");
|
||||
if (Config.tnc.aprsBridgeActive) {
|
||||
if (Config.tnc.enableServer) TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
|
||||
if (Config.tnc.enableSerial) TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
|
||||
}
|
||||
}
|
||||
if (Config.tnc.aprsBridgeActive) {
|
||||
if (Config.tnc.enableServer) TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
|
||||
if (Config.tnc.enableSerial) TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +410,7 @@ namespace APRS_IS_Utils {
|
||||
}
|
||||
|
||||
void firstConnection() {
|
||||
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !aprsIsClient.connected()) {
|
||||
if (Config.aprs_is.active && networkManager->isConnected() && !aprsIsClient.connected()) {
|
||||
connect();
|
||||
while (!passcodeValid) {
|
||||
listenAPRSIS();
|
||||
@@ -396,4 +418,4 @@ namespace APRS_IS_Utils {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -105,9 +105,9 @@ namespace BATTERY_Utils {
|
||||
void getI2CVoltageSensorAddress() {
|
||||
uint8_t err, addr;
|
||||
for(addr = 1; addr < 0x7F; addr++) {
|
||||
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
|
||||
Wire1.beginTransmission(addr);
|
||||
err = Wire1.endTransmission();
|
||||
#ifdef SENSOR_I2C_BUS
|
||||
SENSOR_I2C_BUS.beginTransmission(addr);
|
||||
err = SENSOR_I2C_BUS.endTransmission();
|
||||
#else
|
||||
Wire.beginTransmission(addr);
|
||||
err = Wire.endTransmission();
|
||||
@@ -145,7 +145,7 @@ namespace BATTERY_Utils {
|
||||
}
|
||||
}
|
||||
|
||||
float checkInternalVoltage() {
|
||||
float checkInternalVoltage() {
|
||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||
if(POWER_Utils::isBatteryConnected()) {
|
||||
return POWER_Utils::getBatteryVoltage();
|
||||
@@ -153,8 +153,8 @@ namespace BATTERY_Utils {
|
||||
return 0.0;
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef ADC_CTRL
|
||||
|
||||
#ifdef ADC_CTRL_PIN
|
||||
POWER_Utils::adc_ctrl_ON();
|
||||
#endif
|
||||
|
||||
@@ -177,10 +177,10 @@ namespace BATTERY_Utils {
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
delay(3);
|
||||
delay(3);
|
||||
}
|
||||
|
||||
#ifdef ADC_CTRL
|
||||
#ifdef ADC_CTRL_PIN
|
||||
POWER_Utils::adc_ctrl_OFF();
|
||||
|
||||
#ifdef HELTEC_WP_V1
|
||||
@@ -241,7 +241,7 @@ namespace BATTERY_Utils {
|
||||
#else
|
||||
extVoltage = ((((sampleSum/100.0)* adcReadingTransformation) + readingCorrection) * voltageDividerTransformation) - multiplyCorrection;
|
||||
#endif
|
||||
|
||||
|
||||
return extVoltage; // raw voltage without mapping
|
||||
|
||||
// return mapVoltage(voltage, 5.05, 6.32, 4.5, 5.5); // mapped voltage
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -29,7 +29,7 @@ bool shouldSleepStop = true;
|
||||
bool Configuration::writeFile() {
|
||||
Serial.println("Saving configuration...");
|
||||
|
||||
StaticJsonDocument<3584> data;
|
||||
JsonDocument data;
|
||||
File configFile = SPIFFS.open("/igate_conf.json", "w");
|
||||
|
||||
if (!configFile) {
|
||||
@@ -47,12 +47,14 @@ bool Configuration::writeFile() {
|
||||
|
||||
data["other"]["startupDelay"] = startupDelay;
|
||||
|
||||
data["wifi"]["autoAP"]["enabled"] = wifiAutoAP.enabled;
|
||||
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
|
||||
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
|
||||
|
||||
callsign.trim();
|
||||
callsign.toUpperCase();
|
||||
data["callsign"] = callsign;
|
||||
tacticalCallsign.trim();
|
||||
data["tacticalCallsign"] = tacticalCallsign;
|
||||
|
||||
data["aprs_is"]["active"] = aprs_is.active;
|
||||
data["aprs_is"]["passcode"] = aprs_is.passcode;
|
||||
@@ -86,21 +88,39 @@ bool Configuration::writeFile() {
|
||||
|
||||
data["digi"]["mode"] = digi.mode;
|
||||
data["digi"]["ecoMode"] = digi.ecoMode;
|
||||
if (digi.ecoMode == 1) data["aprs_is"]["active"] = false;
|
||||
#if defined(HAS_A7670)
|
||||
if (digi.ecoMode == 1) data["digi"]["ecoMode"] = 2;
|
||||
#endif
|
||||
data["digi"]["backupDigiMode"] = digi.backupDigiMode;
|
||||
|
||||
data["lora"]["rxActive"] = loramodule.rxActive;
|
||||
data["lora"]["rxFreq"] = loramodule.rxFreq;
|
||||
data["lora"]["rxSpreadingFactor"] = loramodule.rxSpreadingFactor;
|
||||
data["lora"]["rxCodingRate4"] = loramodule.rxCodingRate4;
|
||||
data["lora"]["rxSignalBandwidth"] = loramodule.rxSignalBandwidth;
|
||||
data["lora"]["txActive"] = loramodule.txActive;
|
||||
data["lora"]["txActive"] = loramodule.txActive;
|
||||
data["lora"]["txFreq"] = loramodule.txFreq;
|
||||
data["lora"]["txSpreadingFactor"] = loramodule.txSpreadingFactor;
|
||||
data["lora"]["txCodingRate4"] = loramodule.txCodingRate4;
|
||||
data["lora"]["txSignalBandwidth"] = loramodule.txSignalBandwidth;
|
||||
data["lora"]["power"] = loramodule.power;
|
||||
data["lora"]["txSignalBandwidth"] = loramodule.txSignalBandwidth;
|
||||
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"]["timeout"] = display.timeout;
|
||||
@@ -160,8 +180,6 @@ bool Configuration::writeFile() {
|
||||
|
||||
data["other"]["rememberStationTime"] = rememberStationTime;
|
||||
|
||||
data["other"]["backupDigiMode"] = backupDigiMode;
|
||||
|
||||
serializeJson(data, configFile);
|
||||
configFile.close();
|
||||
return true;
|
||||
@@ -178,8 +196,7 @@ bool Configuration::readFile() {
|
||||
|
||||
if (configFile) {
|
||||
bool needsRewrite = false;
|
||||
StaticJsonDocument<3584> data;
|
||||
|
||||
JsonDocument data;
|
||||
DeserializationError error = deserializeJson(data, configFile);
|
||||
if (error) {
|
||||
Serial.println("Failed to read file, using default configuration");
|
||||
@@ -194,24 +211,28 @@ bool Configuration::readFile() {
|
||||
wifiAPs.push_back(wifiap);
|
||||
}
|
||||
|
||||
if (!data["other"].containsKey("startupDelay")) needsRewrite = true;
|
||||
if (data["other"]["startupDelay"].isNull()) needsRewrite = true;
|
||||
startupDelay = data["other"]["startupDelay"] | 0;
|
||||
|
||||
if (!data["wifi"]["autoAP"].containsKey("password") ||
|
||||
!data["wifi"]["autoAP"].containsKey("timeout")) needsRewrite = true;
|
||||
if (data["wifi"]["autoAP"]["enabled"].isNull() ||
|
||||
data["wifi"]["autoAP"]["password"].isNull() ||
|
||||
data["wifi"]["autoAP"]["timeout"].isNull()) needsRewrite = true;
|
||||
wifiAutoAP.enabled = data["wifi"]["autoAP"]["enabled"] | true;
|
||||
wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890";
|
||||
wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10;
|
||||
|
||||
if (!data.containsKey("callsign")) needsRewrite = true;
|
||||
if (data["callsign"].isNull()) needsRewrite = true;
|
||||
callsign = data["callsign"] | "NOCALL-10";
|
||||
|
||||
if (!data["aprs_is"].containsKey("active") ||
|
||||
!data["aprs_is"].containsKey("passcode") ||
|
||||
!data["aprs_is"].containsKey("server") ||
|
||||
!data["aprs_is"].containsKey("port") ||
|
||||
!data["aprs_is"].containsKey("filter") ||
|
||||
!data["aprs_is"].containsKey("messagesToRF") ||
|
||||
!data["aprs_is"].containsKey("objectsToRF")) needsRewrite = true;
|
||||
if (data["tacticalCallsign"].isNull()) needsRewrite = true;
|
||||
tacticalCallsign = data["tacticalCallsign"] | "";
|
||||
|
||||
if (data["aprs_is"]["active"].isNull() ||
|
||||
data["aprs_is"]["passcode"].isNull() ||
|
||||
data["aprs_is"]["server"].isNull() ||
|
||||
data["aprs_is"]["port"].isNull() ||
|
||||
data["aprs_is"]["filter"].isNull() ||
|
||||
data["aprs_is"]["messagesToRF"].isNull() ||
|
||||
data["aprs_is"]["objectsToRF"].isNull()) needsRewrite = true;
|
||||
aprs_is.active = data["aprs_is"]["active"] | false;
|
||||
aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV";
|
||||
aprs_is.server = data["aprs_is"]["server"] | "rotate.aprs2.net";
|
||||
@@ -220,20 +241,20 @@ bool Configuration::readFile() {
|
||||
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false;
|
||||
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false;
|
||||
|
||||
if (!data["beacon"].containsKey("latitude") ||
|
||||
!data["beacon"].containsKey("longitude") ||
|
||||
!data["beacon"].containsKey("comment") ||
|
||||
!data["beacon"].containsKey("interval") ||
|
||||
!data["beacon"].containsKey("overlay") ||
|
||||
!data["beacon"].containsKey("symbol") ||
|
||||
!data["beacon"].containsKey("path") ||
|
||||
!data["beacon"].containsKey("sendViaAPRSIS") ||
|
||||
!data["beacon"].containsKey("sendViaRF") ||
|
||||
!data["beacon"].containsKey("beaconFreq") ||
|
||||
!data["beacon"].containsKey("statusActive") ||
|
||||
!data["beacon"].containsKey("statusPacket") ||
|
||||
!data["beacon"].containsKey("gpsActive") ||
|
||||
!data["beacon"].containsKey("ambiguityLevel")) needsRewrite = true;
|
||||
if (data["beacon"]["latitude"].isNull() ||
|
||||
data["beacon"]["longitude"].isNull() ||
|
||||
data["beacon"]["comment"].isNull() ||
|
||||
data["beacon"]["interval"].isNull() ||
|
||||
data["beacon"]["overlay"].isNull() ||
|
||||
data["beacon"]["symbol"].isNull() ||
|
||||
data["beacon"]["path"].isNull() ||
|
||||
data["beacon"]["sendViaAPRSIS"].isNull() ||
|
||||
data["beacon"]["sendViaRF"].isNull() ||
|
||||
data["beacon"]["beaconFreq"].isNull() ||
|
||||
data["beacon"]["statusActive"].isNull() ||
|
||||
data["beacon"]["statusPacket"].isNull() ||
|
||||
data["beacon"]["gpsActive"].isNull() ||
|
||||
data["beacon"]["ambiguityLevel"].isNull()) needsRewrite = true;
|
||||
beacon.latitude = data["beacon"]["latitude"] | 0.0;
|
||||
beacon.longitude = data["beacon"]["longitude"] | 0.0;
|
||||
beacon.comment = data["beacon"]["comment"] | "LoRa APRS";
|
||||
@@ -249,62 +270,69 @@ bool Configuration::readFile() {
|
||||
beacon.gpsActive = data["beacon"]["gpsActive"] | false;
|
||||
beacon.ambiguityLevel = data["beacon"]["ambiguityLevel"] | 0;
|
||||
|
||||
if (!data.containsKey("personalNote")) needsRewrite = true;
|
||||
if (data["personalNote"].isNull()) needsRewrite = true;
|
||||
personalNote = data["personalNote"] | "personal note here";
|
||||
|
||||
if (!data.containsKey("blacklist")) needsRewrite = true;
|
||||
if (data["blacklist"].isNull()) needsRewrite = true;
|
||||
blacklist = data["blacklist"] | "station callsign";
|
||||
|
||||
if (!data["digi"].containsKey("mode") ||
|
||||
!data["digi"].containsKey("ecoMode")) needsRewrite = true;
|
||||
if (data["digi"]["mode"].isNull() ||
|
||||
data["digi"]["ecoMode"].isNull() ||
|
||||
data["digi"]["backupDigiMode"].isNull()) needsRewrite = true;
|
||||
digi.mode = data["digi"]["mode"] | 0;
|
||||
digi.ecoMode = data["digi"]["ecoMode"] | 0;
|
||||
if (digi.ecoMode == 1) shouldSleepStop = false;
|
||||
#if defined(HAS_A7670)
|
||||
if (digi.ecoMode == 1) digi.ecoMode = 2;
|
||||
#endif
|
||||
digi.backupDigiMode = data["digi"]["backupDigiMode"] | false;
|
||||
|
||||
if (!data["lora"].containsKey("rxActive") ||
|
||||
!data["lora"].containsKey("rxFreq") ||
|
||||
!data["lora"].containsKey("rxSpreadingFactor") ||
|
||||
!data["lora"].containsKey("rxCodingRate4") ||
|
||||
!data["lora"].containsKey("rxSignalBandwidth") ||
|
||||
!data["lora"].containsKey("txActive") ||
|
||||
!data["lora"].containsKey("txFreq") ||
|
||||
!data["lora"].containsKey("txSpreadingFactor") ||
|
||||
!data["lora"].containsKey("txCodingRate4") ||
|
||||
!data["lora"].containsKey("txSignalBandwidth") ||
|
||||
!data["lora"].containsKey("power")) needsRewrite = true;
|
||||
|
||||
if (data["lora"]["rxActive"].isNull() ||
|
||||
data["lora"]["rxFreq"].isNull() ||
|
||||
data["lora"]["rxSpreadingFactor"].isNull() ||
|
||||
data["lora"]["rxCodingRate4"].isNull() ||
|
||||
data["lora"]["rxSignalBandwidth"].isNull() ||
|
||||
data["lora"]["txActive"].isNull() ||
|
||||
data["lora"]["txFreq"].isNull() ||
|
||||
data["lora"]["txSpreadingFactor"].isNull() ||
|
||||
data["lora"]["txCodingRate4"].isNull() ||
|
||||
data["lora"]["txSignalBandwidth"].isNull() ||
|
||||
data["lora"]["power"].isNull()) needsRewrite = true;
|
||||
loramodule.rxActive = data["lora"]["rxActive"] | true;
|
||||
loramodule.rxFreq = data["lora"]["rxFreq"] | 433775000;
|
||||
loramodule.rxSpreadingFactor = data["lora"]["rxSpreadingFactor"] | 12;
|
||||
loramodule.rxCodingRate4 = data["lora"]["rxCodingRate4"] | 5;
|
||||
loramodule.rxSignalBandwidth = data["lora"]["rxSignalBandwidth"] | 125000;
|
||||
loramodule.rxSignalBandwidth = data["lora"]["rxSignalBandwidth"] | 125000;
|
||||
loramodule.txActive = data["lora"]["txActive"] | false;
|
||||
loramodule.txFreq = data["lora"]["txFreq"] | 433775000;
|
||||
loramodule.txSpreadingFactor = data["lora"]["txSpreadingFactor"] | 12;
|
||||
loramodule.txCodingRate4 = data["lora"]["txCodingRate4"] | 5;
|
||||
loramodule.txSignalBandwidth = data["lora"]["txSignalBandwidth"] | 125000;
|
||||
loramodule.power = data["lora"]["power"] | 20;
|
||||
|
||||
if (!data["display"].containsKey("alwaysOn") ||
|
||||
!data["display"].containsKey("timeout") ||
|
||||
!data["display"].containsKey("turn180")) needsRewrite = true;
|
||||
display.alwaysOn = data["display"]["alwaysOn"] | true;
|
||||
|
||||
if (data["display"]["alwaysOn"].isNull() ||
|
||||
data["display"]["timeout"].isNull() ||
|
||||
data["display"]["turn180"].isNull()) needsRewrite = true;
|
||||
#ifdef HAS_EPAPER
|
||||
display.alwaysOn = true;
|
||||
#else
|
||||
display.alwaysOn = data["display"]["alwaysOn"] | true;
|
||||
#endif
|
||||
display.timeout = data["display"]["timeout"] | 4;
|
||||
display.turn180 = data["display"]["turn180"] | false;
|
||||
|
||||
if (!data["battery"].containsKey("sendInternalVoltage") ||
|
||||
!data["battery"].containsKey("monitorInternalVoltage") ||
|
||||
!data["battery"].containsKey("internalSleepVoltage") ||
|
||||
!data["battery"].containsKey("sendExternalVoltage") ||
|
||||
!data["battery"].containsKey("monitorExternalVoltage") ||
|
||||
!data["battery"].containsKey("externalSleepVoltage") ||
|
||||
!data["battery"].containsKey("useExternalI2CSensor") ||
|
||||
!data["battery"].containsKey("voltageDividerR1") ||
|
||||
!data["battery"].containsKey("voltageDividerR2") ||
|
||||
!data["battery"].containsKey("externalVoltagePin") ||
|
||||
!data["battery"].containsKey("sendVoltageAsTelemetry")) needsRewrite = true;
|
||||
if (data["battery"]["sendInternalVoltage"].isNull() ||
|
||||
data["battery"]["monitorInternalVoltage"].isNull() ||
|
||||
data["battery"]["internalSleepVoltage"].isNull() ||
|
||||
data["battery"]["sendExternalVoltage"].isNull() ||
|
||||
data["battery"]["monitorExternalVoltage"].isNull() ||
|
||||
data["battery"]["externalSleepVoltage"].isNull() ||
|
||||
data["battery"]["useExternalI2CSensor"].isNull() ||
|
||||
data["battery"]["voltageDividerR1"].isNull() ||
|
||||
data["battery"]["voltageDividerR2"].isNull() ||
|
||||
data["battery"]["externalVoltagePin"].isNull() ||
|
||||
data["battery"]["sendVoltageAsTelemetry"].isNull()) needsRewrite = true;
|
||||
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false;
|
||||
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false;
|
||||
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9;
|
||||
@@ -317,38 +345,38 @@ bool Configuration::readFile() {
|
||||
battery.externalVoltagePin = data["battery"]["externalVoltagePin"] | 34;
|
||||
battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false;
|
||||
|
||||
if (!data["wxsensor"].containsKey("active") ||
|
||||
!data["wxsensor"].containsKey("heightCorrection") ||
|
||||
!data["wxsensor"].containsKey("temperatureCorrection")) needsRewrite = true;
|
||||
if (data["wxsensor"]["active"].isNull() ||
|
||||
data["wxsensor"]["heightCorrection"].isNull() ||
|
||||
data["wxsensor"]["temperatureCorrection"].isNull()) needsRewrite = true;
|
||||
wxsensor.active = data["wxsensor"]["active"] | false;
|
||||
wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0;
|
||||
wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0;
|
||||
|
||||
if (!data["syslog"].containsKey("active") ||
|
||||
!data["syslog"].containsKey("server") ||
|
||||
!data["syslog"].containsKey("port") ||
|
||||
!data["syslog"].containsKey("logBeaconOverTCPIP")) needsRewrite = true;
|
||||
if (data["syslog"]["active"].isNull() ||
|
||||
data["syslog"]["server"].isNull() ||
|
||||
data["syslog"]["port"].isNull() ||
|
||||
data["syslog"]["logBeaconOverTCPIP"].isNull()) needsRewrite = true;
|
||||
syslog.active = data["syslog"]["active"] | false;
|
||||
syslog.server = data["syslog"]["server"] | "lora.link9.net";
|
||||
syslog.port = data["syslog"]["port"] | 1514;
|
||||
syslog.logBeaconOverTCPIP = data["syslog"]["logBeaconOverTCPIP"] | false;
|
||||
|
||||
if (!data["tnc"].containsKey("enableServer") ||
|
||||
!data["tnc"].containsKey("enableSerial") ||
|
||||
!data["tnc"].containsKey("acceptOwn") ||
|
||||
!data["tnc"].containsKey("aprsBridgeActive")) needsRewrite = true;
|
||||
if (data["tnc"]["enableServer"].isNull() ||
|
||||
data["tnc"]["enableSerial"].isNull() ||
|
||||
data["tnc"]["acceptOwn"].isNull() ||
|
||||
data["tnc"]["aprsBridgeActive"].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;
|
||||
|
||||
if (!data["mqtt"].containsKey("active") ||
|
||||
!data["mqtt"].containsKey("server") ||
|
||||
!data["mqtt"].containsKey("topic") ||
|
||||
!data["mqtt"].containsKey("username") ||
|
||||
!data["mqtt"].containsKey("password") ||
|
||||
!data["mqtt"].containsKey("port") ||
|
||||
!data["mqtt"].containsKey("beaconOverMqtt")) needsRewrite = true;
|
||||
if (data["mqtt"]["active"].isNull() ||
|
||||
data["mqtt"]["server"].isNull() ||
|
||||
data["mqtt"]["topic"].isNull() ||
|
||||
data["mqtt"]["username"].isNull() ||
|
||||
data["mqtt"]["password"].isNull() ||
|
||||
data["mqtt"]["port"].isNull() ||
|
||||
data["mqtt"]["beaconOverMqtt"].isNull()) needsRewrite = true;
|
||||
mqtt.active = data["mqtt"]["active"] | false;
|
||||
mqtt.server = data["mqtt"]["server"] | "";
|
||||
mqtt.topic = data["mqtt"]["topic"] | "aprs-igate";
|
||||
@@ -356,40 +384,37 @@ bool Configuration::readFile() {
|
||||
mqtt.password = data["mqtt"]["password"] | "";
|
||||
mqtt.port = data["mqtt"]["port"] | 1883;
|
||||
mqtt.beaconOverMqtt = data["mqtt"]["beaconOverMqtt"] | false;
|
||||
|
||||
if (!data["ota"].containsKey("username") ||
|
||||
!data["ota"].containsKey("password")) needsRewrite = true;
|
||||
|
||||
if (data["ota"]["username"].isNull() ||
|
||||
data["ota"]["password"].isNull()) needsRewrite = true;
|
||||
ota.username = data["ota"]["username"] | "";
|
||||
ota.password = data["ota"]["password"] | "";
|
||||
|
||||
if (!data["webadmin"].containsKey("active") ||
|
||||
!data["webadmin"].containsKey("username") ||
|
||||
!data["webadmin"].containsKey("password")) needsRewrite = true;
|
||||
if (data["webadmin"]["active"].isNull() ||
|
||||
data["webadmin"]["username"].isNull() ||
|
||||
data["webadmin"]["password"].isNull()) needsRewrite = true;
|
||||
webadmin.active = data["webadmin"]["active"] | false;
|
||||
webadmin.username = data["webadmin"]["username"] | "admin";
|
||||
webadmin.password = data["webadmin"]["password"] | "";
|
||||
|
||||
if (!data["remoteManagement"].containsKey("managers") ||
|
||||
!data["remoteManagement"].containsKey("rfOnly")) needsRewrite = true;
|
||||
if (data["remoteManagement"]["managers"].isNull() ||
|
||||
data["remoteManagement"]["rfOnly"].isNull()) needsRewrite = true;
|
||||
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
|
||||
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
|
||||
|
||||
if (!data["ntp"].containsKey("server") ||
|
||||
!data["ntp"].containsKey("gmtCorrection")) needsRewrite = true;
|
||||
if (data["ntp"]["server"].isNull() ||
|
||||
data["ntp"]["gmtCorrection"].isNull()) needsRewrite = true;
|
||||
ntp.server = data["ntp"]["server"] | "pool.ntp.org";
|
||||
ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0;
|
||||
|
||||
if (!data["other"].containsKey("rebootMode") ||
|
||||
!data["other"].containsKey("rebootModeTime")) needsRewrite = true;
|
||||
if (data["other"]["rebootMode"].isNull() ||
|
||||
data["other"]["rebootModeTime"].isNull()) needsRewrite = true;
|
||||
rebootMode = data["other"]["rebootMode"] | false;
|
||||
rebootModeTime = data["other"]["rebootModeTime"] | 6;
|
||||
|
||||
if (!data["other"].containsKey("rememberStationTime")) needsRewrite = true;
|
||||
if (data["other"]["rememberStationTime"].isNull()) needsRewrite = true;
|
||||
rememberStationTime = data["other"]["rememberStationTime"] | 30;
|
||||
|
||||
if (!data["other"].containsKey("backupDigiMode")) needsRewrite = true;
|
||||
backupDigiMode = data["other"]["backupDigiMode"] | false;
|
||||
|
||||
if (wifiAPs.size() == 0) { // If we don't have any WiFi's from config we need to add "empty" SSID for AUTO AP
|
||||
WiFi_AP wifiap;
|
||||
wifiap.ssid = "";
|
||||
@@ -404,7 +429,7 @@ bool Configuration::readFile() {
|
||||
writeFile();
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
Serial.println("Config read successfuly");
|
||||
return true;
|
||||
} else {
|
||||
@@ -412,7 +437,7 @@ bool Configuration::readFile() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Configuration::setDefaultValues() {
|
||||
|
||||
WiFi_AP wifiap;
|
||||
@@ -423,10 +448,12 @@ void Configuration::setDefaultValues() {
|
||||
|
||||
startupDelay = 0;
|
||||
|
||||
wifiAutoAP.enabled = true;
|
||||
wifiAutoAP.password = "1234567890";
|
||||
wifiAutoAP.timeout = 10;
|
||||
|
||||
callsign = "N0CALL-10";
|
||||
tacticalCallsign = "";
|
||||
|
||||
aprs_is.active = false;
|
||||
aprs_is.passcode = "XYZVW";
|
||||
@@ -447,19 +474,20 @@ void Configuration::setDefaultValues() {
|
||||
beacon.sendViaAPRSIS = true;
|
||||
beacon.sendViaRF = false;
|
||||
beacon.beaconFreq = 1;
|
||||
|
||||
|
||||
beacon.statusActive = false;
|
||||
beacon.statusPacket = "";
|
||||
beacon.statusPacket = "";
|
||||
|
||||
beacon.gpsActive = false;
|
||||
beacon.ambiguityLevel = 0;
|
||||
|
||||
personalNote = "";
|
||||
personalNote = "";
|
||||
|
||||
blacklist = "";
|
||||
|
||||
digi.mode = 0;
|
||||
digi.ecoMode = 0;
|
||||
digi.backupDigiMode = false;
|
||||
|
||||
loramodule.rxActive = true;
|
||||
loramodule.rxFreq = 433775000;
|
||||
@@ -476,7 +504,7 @@ void Configuration::setDefaultValues() {
|
||||
display.alwaysOn = true;
|
||||
display.timeout = 4;
|
||||
display.turn180 = false;
|
||||
|
||||
|
||||
battery.sendInternalVoltage = false;
|
||||
battery.monitorInternalVoltage = false;
|
||||
battery.internalSleepVoltage = 2.9;
|
||||
@@ -531,12 +559,10 @@ void Configuration::setDefaultValues() {
|
||||
|
||||
rememberStationTime = 30;
|
||||
|
||||
backupDigiMode = false;
|
||||
|
||||
Serial.println("New Data Created... All is Written!");
|
||||
}
|
||||
|
||||
Configuration::Configuration() {
|
||||
void Configuration::setup() {
|
||||
if (!SPIFFS.begin(false)) {
|
||||
Serial.println("SPIFFS Mount Failed");
|
||||
return;
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -38,142 +38,139 @@ extern String fourthLine;
|
||||
extern String fifthLine;
|
||||
extern String sixthLine;
|
||||
extern String seventhLine;
|
||||
extern bool backUpDigiMode;
|
||||
extern bool backupDigiMode;
|
||||
|
||||
|
||||
namespace DIGI_Utils {
|
||||
|
||||
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
|
||||
if (!crossFreq) {
|
||||
String packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
|
||||
String tempPath = path;
|
||||
String cleanPathAsterisks(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("*", "");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path.indexOf("WIDE1-1") != -1 && (Config.digi.mode == 2 || Config.digi.mode == 3)) {
|
||||
tempPath.replace("WIDE1-1", Config.callsign + "*");
|
||||
} else if (path.indexOf("WIDE2-") != -1 && Config.digi.mode == 3) {
|
||||
if (path.indexOf(",WIDE1*") != -1) {
|
||||
tempPath.remove(path.indexOf(",WIDE1*"), 7);
|
||||
}
|
||||
if (path.indexOf("*") != -1) {
|
||||
tempPath.remove(path.indexOf("*"), 1);
|
||||
}
|
||||
if (path.indexOf("WIDE2-1") != -1) {
|
||||
tempPath.replace("WIDE2-1", Config.callsign + "*");
|
||||
} else if (path.indexOf("WIDE2-2") != -1) {
|
||||
tempPath.replace("WIDE2-2", Config.callsign + "*,WIDE2-1");
|
||||
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
|
||||
String stationCallsign = (Config.tacticalCallsign == "" ? Config.callsign : Config.tacticalCallsign);
|
||||
String suffix = thirdParty ? ":}" : ":";
|
||||
int suffixIndex = packet.indexOf(suffix);
|
||||
String packetToRepeat;
|
||||
if (!crossFreq) {
|
||||
int digiMode = Config.digi.mode;
|
||||
String tempPath = path;
|
||||
|
||||
if (tempPath.indexOf("WIDE1-1") != -1 && (digiMode == 2 || digiMode == 3)) { // WIDE1-1
|
||||
if (tempPath.indexOf("*") != -1 ) return ""; // "*" shouldn't be in WIDE1-1 (only) type of packet
|
||||
tempPath.replace("WIDE1-1", stationCallsign + "*");
|
||||
} else if (tempPath.indexOf("WIDE2-") != -1 && digiMode == 3) { // WIDE2-n Digipeater
|
||||
tempPath = cleanPathAsterisks(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");
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
|
||||
packetToRepeat += tempPath;
|
||||
if (thirdParty) {
|
||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":}")));
|
||||
} else {
|
||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":")));
|
||||
}
|
||||
return packetToRepeat;
|
||||
} else { // CrossFreq Digipeater
|
||||
String suffix = thirdParty ? ":}" : ":";
|
||||
String packetToRepeat = packet.substring(0, packet.indexOf(suffix));
|
||||
|
||||
String terms[] = {",WIDE1*", ",WIDE2*", "*"};
|
||||
for (String term : terms) {
|
||||
int index = packetToRepeat.indexOf(term);
|
||||
if (index != -1) {
|
||||
packetToRepeat.remove(index, term.length());
|
||||
}
|
||||
}
|
||||
packetToRepeat = cleanPathAsterisks(packet.substring(0, suffixIndex));
|
||||
if (packetToRepeat.indexOf(stationCallsign) != -1) return ""; // stationCallsign shouldn't be in path
|
||||
packetToRepeat += ",";
|
||||
packetToRepeat += Config.callsign;
|
||||
packetToRepeat += stationCallsign;
|
||||
packetToRepeat += "*";
|
||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(suffix)));
|
||||
return packetToRepeat;
|
||||
}
|
||||
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(suffixIndex));
|
||||
return packetToRepeat;
|
||||
}
|
||||
|
||||
String generateDigipeatedPacket(const String& packet, bool thirdParty){
|
||||
String temp;
|
||||
if (thirdParty) { // only header is used
|
||||
if (thirdParty) { // only header is used
|
||||
const String& header = packet.substring(0, packet.indexOf(":}"));
|
||||
temp = header.substring(header.indexOf(">") + 1);
|
||||
} else {
|
||||
temp = packet.substring(packet.indexOf(">") + 1, packet.indexOf(":"));
|
||||
}
|
||||
if (temp.indexOf(",") > 2) { // checks for path
|
||||
const String& path = temp.substring(temp.indexOf(",") + 1); // after tocall
|
||||
if (Config.digi.mode == 2 || backUpDigiMode) {
|
||||
if (path.indexOf("WIDE1-1") != - 1) {
|
||||
return buildPacket(path, packet, thirdParty, false);
|
||||
} else if (path.indexOf("WIDE1-1") == -1 && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) { // CrossFreq Digi
|
||||
return buildPacket(path, packet, thirdParty, true);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else if (Config.digi.mode == 3) {
|
||||
if (path.indexOf("WIDE1-1") != -1 || path.indexOf("WIDE2-") != -1) {
|
||||
int wide1Index = path.indexOf("WIDE1-1");
|
||||
int wide2Index = path.indexOf("WIDE2-");
|
||||
int commaIndex = temp.indexOf(",");
|
||||
int digiMode = Config.digi.mode;
|
||||
bool crossFreq = abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000; // CrossFreq Digi
|
||||
|
||||
// WIDE1-1 && WIDE2-n / only WIDE1-1 / only WIDE2-n
|
||||
if ((wide1Index != -1 && wide2Index != -1 && wide1Index < wide2Index) || (wide1Index != -1 && wide2Index == -1) || (wide1Index == -1 && wide2Index != -1)) {
|
||||
return buildPacket(path, packet, thirdParty, false);
|
||||
}
|
||||
return "";
|
||||
} else if (path.indexOf("WIDE1-1") == -1 && path.indexOf("WIDE2-") == -1 && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) { // CrossFreq Digi
|
||||
return buildPacket(path, packet, thirdParty, true);
|
||||
} else {
|
||||
return "";
|
||||
if (commaIndex > 2) { // "path" found
|
||||
const String& path = temp.substring(commaIndex + 1);
|
||||
if (digiMode == 2 || backupDigiMode) {
|
||||
bool hasWide = path.indexOf("WIDE1-1") != -1;
|
||||
if (hasWide || crossFreq) {
|
||||
return buildPacket(path, packet, thirdParty, !hasWide);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} else if (temp.indexOf(",") == -1 && (Config.digi.mode == 2 || backUpDigiMode || Config.digi.mode == 3) && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) {
|
||||
return buildPacket("", packet, thirdParty, true);
|
||||
} else {
|
||||
if (digiMode == 3) {
|
||||
int wide1Index = path.indexOf("WIDE1-1");
|
||||
int wide2Index = path.indexOf("WIDE2-");
|
||||
bool hasWide1 = wide1Index != -1;
|
||||
bool hasWide2 = wide2Index != -1;
|
||||
|
||||
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 (crossFreq) return buildPacket(path, packet, thirdParty, true); // CrossFreq (without WIDE)
|
||||
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
if (commaIndex == -1 && (digiMode == 2 || backupDigiMode || digiMode == 3) && crossFreq) return buildPacket("", packet, thirdParty, true); // no "path" but is CrossFreq Digi
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void processLoRaPacket(const String& packet) {
|
||||
if (packet.indexOf("NOGATE") == -1) {
|
||||
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(">"));
|
||||
}
|
||||
if (Sender != Config.callsign) { // Avoid listening to own packets
|
||||
if (!thirdPartyPacket && !Utils::checkValidCallsign(Sender)) {
|
||||
return;
|
||||
}
|
||||
if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2))) {
|
||||
STATION_Utils::updateLastHeard(Sender);
|
||||
Utils::typeOfPacket(temp, 2); // Digi
|
||||
bool queryMessage = false;
|
||||
if (temp.indexOf("::") > 10) { // it's a message
|
||||
String AddresseeAndMessage = temp.substring(temp.indexOf("::") + 2);
|
||||
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||
Addressee.trim();
|
||||
if (Addressee == Config.callsign) { // it's a message for me!
|
||||
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
|
||||
}
|
||||
}
|
||||
if (!queryMessage) {
|
||||
String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
|
||||
if (loraPacket != "") {
|
||||
STATION_Utils::addToOutputPacketBuffer(loraPacket);
|
||||
if (Config.digi.ecoMode != 1) displayToggle(true);
|
||||
lastScreenOn = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packet.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 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 (STATION_Utils::isIn25SegHashBuffer(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);
|
||||
}
|
||||
}
|
||||
if (queryMessage) return; // answer should not be repeated.
|
||||
|
||||
String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
|
||||
if (loraPacket != "") {
|
||||
STATION_Utils::addToOutputPacketBuffer(loraPacket);
|
||||
if (Config.digi.ecoMode != 1) displayToggle(true);
|
||||
lastScreenOn = millis();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifdef HAS_TFT
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite sprite = TFT_eSprite(&tft);
|
||||
|
||||
#ifdef HELTEC_WIRELESS_TRACKER
|
||||
@@ -47,13 +47,17 @@
|
||||
#ifdef HELTEC_WP_V1
|
||||
EInkDisplay_WirelessPaperV1_1 display;
|
||||
#endif
|
||||
/*#ifdef HELTEC_WP_V1_2 // SOON!
|
||||
#ifdef HELTEC_WP_V1_2
|
||||
EInkDisplay_WirelessPaperV1_2 display;
|
||||
#endif*/
|
||||
#endif
|
||||
#ifdef HELTEC_VM_E290
|
||||
EInkDisplay_VisionMasterE290 display;
|
||||
#endif
|
||||
|
||||
String lastEpaperText;
|
||||
#else
|
||||
#include <Adafruit_GFX.h>
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
#include <Adafruit_SH110X.h>
|
||||
Adafruit_SH1106G display(128, 64, &Wire, OLED_RST);
|
||||
#else
|
||||
@@ -88,15 +92,22 @@ void displaySetup() {
|
||||
tft.setTextFont(0);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
|
||||
sprite.createSprite(320,240);
|
||||
sprite.createSprite(320, 240);
|
||||
#else
|
||||
sprite.createSprite(160,80);
|
||||
sprite.createSprite(160, 80);
|
||||
#endif
|
||||
#else
|
||||
#ifdef HAS_EPAPER
|
||||
display.landscape();
|
||||
display.printCenter("LoRa APRS iGate Initialising...");
|
||||
if (Config.display.turn180) display.setRotation(2);
|
||||
if (Config.display.turn180) {
|
||||
#if defined(HELTEC_VM_E290) || defined(HELTEC_WP_V1)
|
||||
display.setRotation(3);
|
||||
#endif
|
||||
#if defined(HELTEC_WP_V1_2)
|
||||
display.setRotation(1);
|
||||
#endif
|
||||
}
|
||||
display.update();
|
||||
#else
|
||||
#ifdef OLED_DISPLAY_HAS_RST_PIN
|
||||
@@ -106,7 +117,7 @@ void displaySetup() {
|
||||
digitalWrite(OLED_RST, HIGH);
|
||||
#endif
|
||||
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
if (display.begin(0x3c, false)) {
|
||||
displayFound = true;
|
||||
if (Config.display.turn180) display.setRotation(2);
|
||||
@@ -146,7 +157,7 @@ void displayToggle(bool toggle) {
|
||||
display.printCenter("EPAPER Display Disabled by toggle...");
|
||||
display.update();
|
||||
#else
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
if (displayFound) display.oled_command(SH110X_DISPLAYON);
|
||||
#else
|
||||
if (displayFound) display.ssd1306_command(SSD1306_DISPLAYON);
|
||||
@@ -158,15 +169,14 @@ void displayToggle(bool toggle) {
|
||||
digitalWrite(TFT_BL, LOW);
|
||||
#else
|
||||
#ifdef HAS_EPAPER
|
||||
display.printCenter("Enabled EPAPER Display...");
|
||||
display.update();
|
||||
#else
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
if (displayFound) display.oled_command(SH110X_DISPLAYOFF);
|
||||
#else
|
||||
if (displayFound) display.ssd1306_command(SSD1306_DISPLAYOFF);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -196,7 +206,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
|
||||
}
|
||||
|
||||
sprite.pushSprite(0,0);
|
||||
sprite.pushSprite(0, 0);
|
||||
#else
|
||||
#ifdef HAS_EPAPER
|
||||
display.clearMemory();
|
||||
@@ -212,7 +222,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
#else
|
||||
if (displayFound) {
|
||||
display.clearDisplay();
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
display.setTextColor(SH110X_WHITE);
|
||||
#else
|
||||
display.setTextColor(WHITE);
|
||||
@@ -224,7 +234,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
display.setCursor(0, 8 + (8 * i));
|
||||
display.println(*lines[i]);
|
||||
}
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
display.setContrast(1);
|
||||
#else
|
||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
||||
@@ -261,7 +271,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
|
||||
}
|
||||
|
||||
sprite.pushSprite(0,0);
|
||||
sprite.pushSprite(0, 0);
|
||||
#else
|
||||
#ifdef HAS_EPAPER
|
||||
lastEpaperText = header + line1 + line2 + line3 + line4 + line5 + line6;
|
||||
@@ -278,7 +288,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
#else
|
||||
if (displayFound) {
|
||||
display.clearDisplay();
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
display.setTextColor(SH110X_WHITE);
|
||||
#else
|
||||
display.setTextColor(WHITE);
|
||||
@@ -291,7 +301,7 @@ void displayShow(const String& header, const String& line1, const String& line2,
|
||||
display.setCursor(0, 16 + (8 * i));
|
||||
display.println(*lines[i]);
|
||||
}
|
||||
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||
#ifdef HAS_SH1106
|
||||
display.setContrast(1);
|
||||
#else
|
||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -34,6 +34,7 @@
|
||||
extern Configuration Config;
|
||||
extern HardwareSerial gpsSerial;
|
||||
extern TinyGPSPlus gps;
|
||||
extern bool stationCallsignIsValid;
|
||||
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
||||
|
||||
|
||||
@@ -44,20 +45,31 @@ namespace GPS_Utils {
|
||||
}
|
||||
|
||||
void generateBeacons() {
|
||||
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
|
||||
displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000);
|
||||
Config.loramodule.txActive = false;
|
||||
Config.aprs_is.messagesToRF = false;
|
||||
Config.aprs_is.objectsToRF = false;
|
||||
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);
|
||||
|
||||
if (Config.callsign.indexOf("NOCALL-10") != 0) {
|
||||
if (!stationCallsignIsValid) {
|
||||
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.digi.backupDigiMode = false;
|
||||
} else if (stationCallsignIsValid && Config.tacticalCallsign != "") {
|
||||
beaconPacket = APRSPacketLib::generateBasePacket(Config.tacticalCallsign, "APLRG1", Config.beacon.path);
|
||||
Config.aprs_is.active = false;
|
||||
Config.beacon.sendViaAPRSIS = false;
|
||||
Config.digi.backupDigiMode = false;
|
||||
}
|
||||
} else {
|
||||
Config.beacon.sendViaAPRSIS = 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 += ",qAC:!";
|
||||
iGateBeaconPacket += ",qAC:=";
|
||||
iGateBeaconPacket += Config.beacon.overlay;
|
||||
iGateBeaconPacket += encodedGPS;
|
||||
|
||||
@@ -122,46 +134,55 @@ namespace GPS_Utils {
|
||||
}
|
||||
|
||||
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(Latitude.indexOf(".") + 1, Latitude.indexOf(".") + 3).toFloat() / (60*100);
|
||||
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(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3).toFloat() / (60*100);
|
||||
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);
|
||||
} else {
|
||||
const uint8_t ENCODED_BYTE_OFFSET = 14; // Offset for encoded data in the packet
|
||||
int indexOfExclamation = packet.indexOf(":!");
|
||||
int indexOfEqual = packet.indexOf(":=");
|
||||
uint8_t encodedBytePosition = 0;
|
||||
if (indexOfExclamation > 10) { // Determine the position where encoded data starts
|
||||
encodedBytePosition = indexOfExclamation + ENCODED_BYTE_OFFSET;
|
||||
} else if (indexOfEqual > 10) {
|
||||
encodedBytePosition = indexOfEqual + ENCODED_BYTE_OFFSET;
|
||||
}
|
||||
if (indexOfAt > 10) return getReceivedGPS(packet);
|
||||
|
||||
if (encodedBytePosition != 0) {
|
||||
char currentChar = packet[encodedBytePosition];
|
||||
if (currentChar == 'G' || currentChar == 'Q' || currentChar == '[' || currentChar == 'H' || currentChar == 'X' || currentChar == '3') {
|
||||
return decodeEncodedGPS(packet); // If valid encoded data position is found, decode it
|
||||
} else {
|
||||
return getReceivedGPS(packet);
|
||||
}
|
||||
} else {
|
||||
return " _ / _ / _ ";
|
||||
}
|
||||
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 " _ / _ / _ ";
|
||||
}
|
||||
|
||||
void setup() {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -30,29 +30,19 @@ bool validateKISSFrame(const String& kissFormattedFrame) {
|
||||
|
||||
String encodeAddressAX25(String tnc2Address) {
|
||||
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
||||
|
||||
if (tnc2Address.indexOf('-') == -1) {
|
||||
if (hasBeenDigipited) {
|
||||
tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
|
||||
}
|
||||
|
||||
if (hasBeenDigipited) tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
|
||||
tnc2Address += "-0";
|
||||
}
|
||||
|
||||
int separatorIndex = tnc2Address.indexOf('-');
|
||||
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||
|
||||
int separatorIndex = tnc2Address.indexOf('-');;
|
||||
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||
String kissAddress = "";
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
char addressChar;
|
||||
if (tnc2Address.length() > i && i < separatorIndex) {
|
||||
addressChar = tnc2Address.charAt(i);
|
||||
} else {
|
||||
addressChar = ' ';
|
||||
}
|
||||
char addressChar = ' ';
|
||||
if (tnc2Address.length() > i && i < separatorIndex) addressChar = tnc2Address.charAt(i);
|
||||
kissAddress += (char)(addressChar << 1);
|
||||
}
|
||||
|
||||
kissAddress += (char)((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
||||
return kissAddress;
|
||||
}
|
||||
@@ -131,8 +121,9 @@ String encodeKISS(const String& frame) {
|
||||
|
||||
if (validateTNC2Frame(frame)) {
|
||||
String address = "";
|
||||
bool dstAddresWritten = false;
|
||||
for (int p = 0; p <= frame.indexOf(':'); p++) {
|
||||
bool dstAddresWritten = false;
|
||||
int colonFrameIndex = frame.indexOf(':');
|
||||
for (int p = 0; p <= colonFrameIndex; p++) {
|
||||
char currentChar = frame.charAt(p);
|
||||
if (currentChar == ':' || currentChar == '>' || currentChar == ',') {
|
||||
if (!dstAddresWritten && (currentChar == ',' || currentChar == ':')) {
|
||||
@@ -151,7 +142,7 @@ String encodeKISS(const String& frame) {
|
||||
ax25Frame.setCharAt(ax25Frame.length() - 1, (char)(lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
||||
ax25Frame += (char)APRS_CONTROL_FIELD;
|
||||
ax25Frame += (char)APRS_INFORMATION_FIELD;
|
||||
ax25Frame += frame.substring(frame.indexOf(':') + 1);
|
||||
ax25Frame += frame.substring(colonFrameIndex + 1);
|
||||
}
|
||||
|
||||
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <RadioLib.h>
|
||||
#include <WiFi.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "aprs_is_utils.h"
|
||||
#include "station_utils.h"
|
||||
#include "board_pinout.h"
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
extern uint32_t lastRxTime;
|
||||
extern bool packetIsBeacon;
|
||||
|
||||
@@ -43,7 +44,7 @@ bool transmitFlag = true;
|
||||
#ifdef HAS_SX1268
|
||||
#if defined(LIGHTGATEWAY_1_0) || defined(LIGHTGATEWAY_PLUS_1_0)
|
||||
SPIClass loraSPI(FSPI);
|
||||
SX1268 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN, loraSPI);
|
||||
SX1268 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN, loraSPI);
|
||||
#else
|
||||
SX1268 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
|
||||
#endif
|
||||
@@ -81,9 +82,7 @@ namespace LoRa_Utils {
|
||||
radio.XTAL = true;
|
||||
#endif
|
||||
int state = radio.begin(freq);
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Utils::println("Initializing LoRa Module");
|
||||
} else {
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
Utils::println("Starting LoRa failed! State: " + String(state));
|
||||
while (true);
|
||||
}
|
||||
@@ -102,11 +101,11 @@ namespace LoRa_Utils {
|
||||
while (true);
|
||||
}
|
||||
#endif*/
|
||||
|
||||
|
||||
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
||||
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
||||
float signalBandwidth = Config.loramodule.rxSignalBandwidth/1000;
|
||||
radio.setBandwidth(signalBandwidth);
|
||||
float signalBandwidth = Config.loramodule.rxSignalBandwidth / 1000;
|
||||
radio.setBandwidth(signalBandwidth);
|
||||
radio.setCRC(true);
|
||||
|
||||
#if (defined(RADIO_RXEN) && defined(RADIO_TXEN)) // QRP Labs LightGateway has 400M22S (SX1268)
|
||||
@@ -151,21 +150,21 @@ namespace LoRa_Utils {
|
||||
}
|
||||
|
||||
void changeFreqTx() {
|
||||
delay(300);
|
||||
float freq = (float)Config.loramodule.txFreq / 1000000;
|
||||
radio.setFrequency(freq);
|
||||
radio.setSpreadingFactor(Config.loramodule.txSpreadingFactor);
|
||||
radio.setCodingRate(Config.loramodule.txCodingRate4);
|
||||
radio.setBandwidth(Config.loramodule.txSignalBandwidth);
|
||||
float signalBandwidth = Config.loramodule.txSignalBandwidth / 1000;
|
||||
radio.setBandwidth(signalBandwidth);
|
||||
}
|
||||
|
||||
void changeFreqRx() {
|
||||
delay(300);
|
||||
float freq = (float)Config.loramodule.rxFreq / 1000000;
|
||||
radio.setFrequency(freq);
|
||||
radio.setSpreadingFactor(Config.loramodule.rxSpreadingFactor);
|
||||
radio.setCodingRate(Config.loramodule.rxCodingRate4);
|
||||
radio.setBandwidth(Config.loramodule.rxSignalBandwidth);
|
||||
float signalBandwidth = Config.loramodule.rxSignalBandwidth / 1000;
|
||||
radio.setBandwidth(signalBandwidth);
|
||||
}
|
||||
|
||||
void sendNewPacket(const String& newPacket) {
|
||||
@@ -176,14 +175,14 @@ namespace LoRa_Utils {
|
||||
changeFreqTx();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
if (Config.digi.ecoMode != 1) digitalWrite(INTERNAL_LED_PIN, HIGH); // disabled in Ultra Eco Mode
|
||||
#endif
|
||||
int state = radio.transmit("\x3c\xff\x01" + newPacket);
|
||||
transmitFlag = true;
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX
|
||||
}
|
||||
Utils::print("---> LoRa Packet Tx : ");
|
||||
@@ -245,7 +244,7 @@ namespace LoRa_Utils {
|
||||
receivedPackets.push_back(receivedPacket);
|
||||
}
|
||||
|
||||
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX
|
||||
}
|
||||
} else {
|
||||
@@ -259,7 +258,7 @@ namespace LoRa_Utils {
|
||||
snr = radio.getSNR();
|
||||
freqError = radio.getFrequencyError();
|
||||
Utils::println(F("CRC error!"));
|
||||
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC
|
||||
}
|
||||
packet = "";
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <PubSubClient.h>
|
||||
#include "configuration.h"
|
||||
#include "station_utils.h"
|
||||
@@ -95,7 +95,7 @@ namespace MQTT_Utils {
|
||||
void setup() {
|
||||
if (!Config.mqtt.active) return;
|
||||
pubSub.setClient(mqttClient);
|
||||
pubSub.setCallback(receivedFromMqtt);
|
||||
pubSub.setCallback(receivedFromMqtt);
|
||||
}
|
||||
|
||||
}
|
||||
333
src/network_manager.cpp
Normal file
333
src/network_manager.cpp
Normal file
@@ -0,0 +1,333 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "network_manager.h"
|
||||
|
||||
// Constructor
|
||||
NetworkManager::NetworkManager() { }
|
||||
|
||||
// Destructor
|
||||
NetworkManager::~NetworkManager() { }
|
||||
|
||||
// Private methods
|
||||
|
||||
int NetworkManager::_findWiFiNetworkIndex(const String& ssid) const {
|
||||
for (size_t i = 0; i < _wifiNetworks.size(); i++) {
|
||||
if (_wifiNetworks[i].ssid == ssid) {
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool NetworkManager::_connectWiFi(const WiFiNetwork& network) {
|
||||
if (network.ssid.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_wifiSTAmode = true;
|
||||
|
||||
if (!_hostName.isEmpty()) {
|
||||
WiFi.setHostname(_hostName.c_str());
|
||||
}
|
||||
|
||||
WiFi.mode(_wifiAPmode ? WIFI_AP_STA : WIFI_STA);
|
||||
|
||||
Serial.println("[NM] Attempting to connect to WiFi: " + network.ssid);
|
||||
WiFi.begin(network.ssid.c_str(), network.psk.c_str());
|
||||
|
||||
Serial.print("[NM] Connecting ");
|
||||
|
||||
int attempts = 0;
|
||||
while (!isWiFiConnected() && attempts < 10) {
|
||||
delay(500);
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,HIGH);
|
||||
#endif
|
||||
Serial.print('.');
|
||||
delay(500);
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,LOW);
|
||||
#endif
|
||||
attempts++;
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
if (isWiFiConnected()) return true;
|
||||
|
||||
Serial.println("[NM] Failed to connect to WiFi after " + String(attempts) + " attempts. SSID: " + network.ssid);
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkManager::_processAPTimeout() {
|
||||
if (!_wifiAPmode || _apTimeout == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If any station is connected, reset the timer
|
||||
if (WiFi.softAPgetStationNum() > 0) {
|
||||
_apStartup = millis();
|
||||
return;
|
||||
}
|
||||
|
||||
if (millis() - _apStartup > _apTimeout) {
|
||||
Serial.println("[NM] AP timeout reached. Disabling AP mode.");
|
||||
disableAP();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkManager::_onNetworkEvent(arduino_event_id_t event, arduino_event_info_t /*info*/) {
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
Serial.println("[NM] ETH Started");
|
||||
if (!_hostName.isEmpty()) {
|
||||
Serial.println("[NM] ETH Setting Hostname: " + _hostName);
|
||||
ETH.setHostname(_hostName.c_str());
|
||||
}
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
Serial.println("[NM] ETH Connected");
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
Serial.println("[NM] ETH Got IP");
|
||||
_ethernetConnected = true;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
Serial.println("[NM] ETH Disconnected");
|
||||
_ethernetConnected = false;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
Serial.println("[NM] ETH Stopped");
|
||||
_ethernetConnected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
bool NetworkManager::setup() {
|
||||
Serial.println("[NM] Initializing Networking...");
|
||||
|
||||
WiFi.onEvent(
|
||||
[this](arduino_event_id_t event, arduino_event_info_t info) {
|
||||
_onNetworkEvent(event, info);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkManager::loop() {
|
||||
if (_wifiAPmode) {
|
||||
_processAPTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkManager::setHostName(const String& hostName) {
|
||||
_hostName = hostName;
|
||||
}
|
||||
|
||||
// WiFi methods
|
||||
|
||||
bool NetworkManager::setupAP(String apName, String apPsk) {
|
||||
_wifiAPmode = true;
|
||||
|
||||
Serial.println("[NM] Starting AP mode: " + apName);
|
||||
|
||||
// Full WiFi reset sequence
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
delay(200);
|
||||
|
||||
// Set up AP mode with optimized settings
|
||||
WiFi.mode(WIFI_AP);
|
||||
|
||||
bool apStarted = WiFi.softAP(apName.c_str(), apPsk.c_str());
|
||||
delay(1000); // Give AP time to fully initialize
|
||||
|
||||
if (apStarted) {
|
||||
Serial.println("[NM] AP setup successful");
|
||||
_apStartup = millis();
|
||||
}
|
||||
else {
|
||||
Serial.println("[NM] AP setup failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
IPAddress apIP = getWiFiAPIP();
|
||||
Serial.println("[NM] AP IP assigned: " + apIP.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetworkManager::disableAP() {
|
||||
WiFi.mode(_wifiSTAmode ? WIFI_STA : WIFI_OFF);
|
||||
_wifiAPmode = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkManager::setAPTimeout(unsigned long timeout) {
|
||||
Serial.println("[NM] Setting AP timeout to " + String(timeout / 1000) + " sec");
|
||||
_apTimeout = timeout;
|
||||
}
|
||||
|
||||
void NetworkManager::addWiFiNetwork(const String& ssid, const String& psk) {
|
||||
if (ssid.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = _findWiFiNetworkIndex(ssid);
|
||||
if (index >= 0) {
|
||||
Serial.println("[NM] Updating WiFi network: " + ssid);
|
||||
_wifiNetworks[static_cast<size_t>(index)].psk = psk;
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("[NM] Adding WiFi network: " + ssid);
|
||||
WiFiNetwork network;
|
||||
network.ssid = ssid;
|
||||
network.psk = psk;
|
||||
_wifiNetworks.push_back(network);
|
||||
}
|
||||
|
||||
void NetworkManager::clearWiFiNetworks() {
|
||||
_wifiNetworks.clear();
|
||||
}
|
||||
|
||||
bool NetworkManager::hasWiFiNetworks() const {
|
||||
return !_wifiNetworks.empty();
|
||||
}
|
||||
|
||||
size_t NetworkManager::getWiFiNetworkCount() const {
|
||||
return _wifiNetworks.size();
|
||||
}
|
||||
|
||||
bool NetworkManager::connectWiFi() {
|
||||
if (_wifiNetworks.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _wifiNetworks.size(); i++) {
|
||||
disconnectWiFi();
|
||||
if (_connectWiFi(_wifiNetworks[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetworkManager::connectWiFi(const String& ssid, const String& psk) {
|
||||
addWiFiNetwork(ssid, psk);
|
||||
return connectWiFi();
|
||||
}
|
||||
|
||||
bool NetworkManager::disconnectWiFi() {
|
||||
WiFi.disconnect(true);
|
||||
WiFi.mode(_wifiAPmode ? WIFI_AP : WIFI_OFF);
|
||||
|
||||
_wifiSTAmode = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
String NetworkManager::getWiFiSSID() const {
|
||||
return WiFi.SSID();
|
||||
}
|
||||
|
||||
String NetworkManager::getWiFiAPSSID() const {
|
||||
return WiFi.softAPSSID();
|
||||
}
|
||||
|
||||
IPAddress NetworkManager::getWiFiIP() const {
|
||||
return WiFi.localIP();
|
||||
}
|
||||
|
||||
IPAddress NetworkManager::getWiFiAPIP() const {
|
||||
return WiFi.softAPIP();
|
||||
}
|
||||
|
||||
wifi_mode_t NetworkManager::getWiFiMode() const {
|
||||
return WiFi.getMode();
|
||||
}
|
||||
|
||||
uint8_t* NetworkManager::getWiFimacAddress(uint8_t* mac) {
|
||||
return WiFi.macAddress(mac);
|
||||
}
|
||||
|
||||
String NetworkManager::getWiFimacAddress(void) const {
|
||||
return WiFi.macAddress();
|
||||
}
|
||||
|
||||
// Ethernet methods
|
||||
bool NetworkManager::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) {
|
||||
_ethernetMode = true;
|
||||
Serial.println("[NM] Setting up Ethernet...");
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
// SDK 5.x (Arduino SDK 3.x)
|
||||
#pragma message("Compiling ETH init: SDK 5.x (Arduino core 3.x)")
|
||||
return ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode, use_mac_from_efuse);
|
||||
#else
|
||||
// SDK 4.x (Arduino SDK 2.x)
|
||||
#pragma message("Compiling ETH init: SDK 4.x (Arduino core 2.x)")
|
||||
return ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode, use_mac_from_efuse);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NetworkManager::setEthernetIP(const String& staticIP, const String& gateway, const String& subnet, const String& dns1, const String& dns2) {
|
||||
if (staticIP.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPAddress ip, gw, sn, d1, d2;
|
||||
if (!ip.fromString(staticIP) || !gw.fromString(gateway) || !sn.fromString(subnet)) {
|
||||
Serial.println("[NM] Invalid static IP configuration");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dns1.isEmpty() && d1.fromString(dns1)) {
|
||||
if (!dns2.isEmpty() && d2.fromString(dns2)) {
|
||||
ETH.config(ip, gw, sn, d1, d2);
|
||||
} else {
|
||||
ETH.config(ip, gw, sn, d1);
|
||||
}
|
||||
} else {
|
||||
ETH.config(ip, gw, sn);
|
||||
}
|
||||
|
||||
Serial.println("[NM] Ethernet static IP: " + staticIP);
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress NetworkManager::getEthernetIP() const {
|
||||
return ETH.localIP();
|
||||
}
|
||||
|
||||
String NetworkManager::getEthernetMACAddress() const {
|
||||
return ETH.macAddress();
|
||||
}
|
||||
|
||||
// Check if network is available
|
||||
bool NetworkManager::isConnected() const {
|
||||
return isWiFiConnected() || isEthernetConnected() || isModemConnected();
|
||||
}
|
||||
|
||||
// Check if WiFi is connected
|
||||
bool NetworkManager::isWiFiConnected() const {
|
||||
return _wifiSTAmode ? WiFi.status() == WL_CONNECTED : false;
|
||||
}
|
||||
|
||||
bool NetworkManager::isWifiAPActive() const {
|
||||
return _wifiAPmode;
|
||||
}
|
||||
|
||||
// Check if Ethernet is connected
|
||||
bool NetworkManager::isEthernetConnected() const {
|
||||
return _ethernetMode && _ethernetConnected && ETH.linkUp();
|
||||
}
|
||||
|
||||
// Check if Modem is connected
|
||||
bool NetworkManager::isModemConnected() const {
|
||||
// Implement Modem connection check logic here
|
||||
return false;
|
||||
}
|
||||
@@ -1,52 +1,66 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <NTPClient.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <WiFi.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "ntp_utils.h"
|
||||
#include "time.h"
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
|
||||
extern NetworkManager *networkManager;
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient* timeClient;
|
||||
NTPClient* timeClient = nullptr;
|
||||
|
||||
|
||||
namespace NTP_Utils {
|
||||
|
||||
void setup() {
|
||||
if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") {
|
||||
bool setup() {
|
||||
if (networkManager->isConnected() && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") {
|
||||
int gmt = Config.ntp.gmtCorrection * 3600;
|
||||
Serial.println("[NTP] Setting up, TZ offset: " + String(gmt) + " Server: " + Config.ntp.server);
|
||||
timeClient = new NTPClient(ntpUDP, Config.ntp.server.c_str(), gmt, 15 * 60 * 1000); // Update interval 15 min
|
||||
timeClient->begin();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void update() {
|
||||
if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") timeClient->update();
|
||||
if (!networkManager->isConnected() || Config.digi.ecoMode != 0 || Config.callsign == "NOCALL-10") {
|
||||
return;
|
||||
}
|
||||
if (timeClient == nullptr) {
|
||||
if (!setup()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
timeClient->update();
|
||||
}
|
||||
|
||||
String getFormatedTime() {
|
||||
if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0) return timeClient->getFormattedTime();
|
||||
if (networkManager->isConnected() && Config.digi.ecoMode == 0 && timeClient != nullptr) {
|
||||
return timeClient->getFormattedTime();
|
||||
}
|
||||
return "DigiEcoMode Active";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "battery_utils.h"
|
||||
#include "board_pinout.h"
|
||||
#include "power_utils.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||
@@ -43,48 +44,28 @@
|
||||
#endif
|
||||
|
||||
extern Configuration Config;
|
||||
extern bool stationCallsignIsValid;
|
||||
|
||||
|
||||
namespace POWER_Utils {
|
||||
|
||||
#ifdef VEXT_CTRL
|
||||
void vext_ctrl_ON() {
|
||||
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
|
||||
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
|
||||
#endif
|
||||
#if defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3)
|
||||
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vext_ctrl_OFF() {
|
||||
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
|
||||
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? HIGH : LOW);
|
||||
#endif
|
||||
#if defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3)
|
||||
digitalWrite(VEXT_CTRL, Config.digi.ecoMode == 1 ? LOW : HIGH);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ADC_CTRL
|
||||
#ifdef ADC_CTRL_PIN
|
||||
void adc_ctrl_ON() {
|
||||
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
|
||||
digitalWrite(ADC_CTRL, HIGH);
|
||||
#endif
|
||||
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP_V1)
|
||||
digitalWrite(ADC_CTRL, LOW);
|
||||
#endif
|
||||
digitalWrite(ADC_CTRL_PIN, ADC_CTRL_ON_STATE);
|
||||
}
|
||||
|
||||
void adc_ctrl_OFF() {
|
||||
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
|
||||
digitalWrite(ADC_CTRL, LOW);
|
||||
#endif
|
||||
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP_V1)
|
||||
digitalWrite(ADC_CTRL, HIGH);
|
||||
#endif
|
||||
digitalWrite(ADC_CTRL_PIN, !ADC_CTRL_ON_STATE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VEXT_CTRL_PIN
|
||||
void vext_ctrl_ON() {
|
||||
digitalWrite(VEXT_CTRL_PIN, Config.digi.ecoMode == 1 ? !VEXT_CTRL_ON_STATE : VEXT_CTRL_ON_STATE);
|
||||
}
|
||||
|
||||
void vext_ctrl_OFF() {
|
||||
digitalWrite(VEXT_CTRL_PIN, Config.digi.ecoMode == 1 ? VEXT_CTRL_ON_STATE : !VEXT_CTRL_ON_STATE);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -112,7 +93,7 @@ namespace POWER_Utils {
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void activateGPS() {
|
||||
#ifdef HAS_AXP192
|
||||
@@ -282,8 +263,8 @@ namespace POWER_Utils {
|
||||
pinMode(Config.battery.externalVoltagePin, INPUT);
|
||||
}
|
||||
|
||||
#ifdef VEXT_CTRL
|
||||
pinMode(VEXT_CTRL,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
|
||||
#ifdef VEXT_CTRL_PIN
|
||||
pinMode(VEXT_CTRL_PIN,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
|
||||
vext_ctrl_ON();
|
||||
#endif
|
||||
|
||||
@@ -291,8 +272,8 @@ namespace POWER_Utils {
|
||||
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) activateGPS();
|
||||
#endif
|
||||
|
||||
#ifdef ADC_CTRL
|
||||
pinMode(ADC_CTRL, OUTPUT);
|
||||
#ifdef ADC_CTRL_PIN
|
||||
pinMode(ADC_CTRL_PIN, OUTPUT);
|
||||
adc_ctrl_OFF();
|
||||
#endif
|
||||
|
||||
@@ -315,17 +296,14 @@ namespace POWER_Utils {
|
||||
Wire.begin(OLED_SDA, OLED_SCL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIRE_WITH_BOARD_I2C_PINS
|
||||
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
|
||||
#ifdef SENSOR_I2C_BUS
|
||||
SENSOR_I2C_BUS.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
|
||||
#endif
|
||||
|
||||
delay(1000);
|
||||
BATTERY_Utils::setup();
|
||||
BATTERY_Utils::startupBatteryHealth();
|
||||
stationCallsignIsValid = Utils::callsignIsValid(Config.callsign);
|
||||
setCpuFrequencyMhz(80);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -41,7 +41,7 @@ namespace QUERY_Utils {
|
||||
String queryQuestion = query;
|
||||
queryQuestion.toUpperCase();
|
||||
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") {
|
||||
answer.concat("CA2RXU_LoRa_iGate v");
|
||||
answer.concat(versionNumber);
|
||||
@@ -49,9 +49,9 @@ namespace QUERY_Utils {
|
||||
answer.concat(versionDate);
|
||||
} else if (queryQuestion == "?APRSP") {
|
||||
answer.concat("iGate QTH: ");
|
||||
answer.concat(String(Config.beacon.latitude,3));
|
||||
answer.concat(String(Config.beacon.latitude,2));
|
||||
answer.concat(" ");
|
||||
answer.concat(String(Config.beacon.longitude,3));
|
||||
answer.concat(String(Config.beacon.longitude,2));
|
||||
} else if (queryQuestion == "?APRSL") {
|
||||
if (lastHeardStations.size() == 0) {
|
||||
char answerArray[50];
|
||||
@@ -66,21 +66,25 @@ namespace QUERY_Utils {
|
||||
} else if (queryQuestion == "?APRSSR") {
|
||||
char signalData[35];
|
||||
snprintf(signalData, sizeof(signalData), " %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
|
||||
answer.concat(signalData);
|
||||
answer.concat(signalData);
|
||||
} /*else if (queryQuestion.indexOf("?APRSH") == 0) {
|
||||
// sacar callsign despues de ?APRSH
|
||||
Serial.println("escuchaste a X estacion? en las ultimas 24 o 8 horas?");
|
||||
answer.concat("?APRSH on development 73!");
|
||||
} *//*else if (queryQuestion.indexOf("?WHERE") == 0) {
|
||||
} *//*else if (queryQuestion.indexOf("?WHERE") == 0) {
|
||||
// agregar callsign para completar donde esta X callsign --> posicion
|
||||
Serial.println("estaciones escuchadas directo (ultimos 30 min)");
|
||||
answer.concat("?WHERE on development 73!");
|
||||
} */
|
||||
else if (STATION_Utils::isManager(station) && (!queryFromAPRSIS || !Config.remoteManagement.rfOnly)) {
|
||||
if (queryQuestion.indexOf("?EM=OFF") == 0) {
|
||||
if ((Config.digi.mode == 2 || Config.digi.mode == 3) && Config.loramodule.txActive && Config.loramodule.rxActive && !Config.aprs_is.active) {
|
||||
if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) { // Exit Digipeater EcoMode or Digipeater without WiFiAP
|
||||
answer = (Config.digi.ecoMode == 1) ? "DigiEcoMode:OFF" : "Digipeater + WiFiAP enabled";
|
||||
int digiMode = Config.digi.mode;
|
||||
int digiEcoMode = Config.digi.ecoMode;
|
||||
int radioTxActive = Config.loramodule.txActive;
|
||||
bool onlyRadioActive = radioTxActive && Config.loramodule.rxActive && !Config.aprs_is.active;
|
||||
if (queryQuestion.startsWith("?EM=OFF")) {
|
||||
if ((digiMode == 2 || digiMode == 3) && onlyRadioActive) {
|
||||
if (digiEcoMode == 1 || digiEcoMode == 2) { // Exit Digipeater EcoMode or Digipeater without WiFiAP
|
||||
answer = (digiEcoMode == 1) ? "DigiEcoMode:OFF" : "Digipeater + WiFiAP enabled";
|
||||
Config.digi.ecoMode = 0;
|
||||
Config.display.alwaysOn = true;
|
||||
Config.display.timeout = 10;
|
||||
@@ -92,9 +96,9 @@ namespace QUERY_Utils {
|
||||
} else {
|
||||
answer = "Digipeater Mode control not possible";
|
||||
}
|
||||
} else if (queryQuestion.indexOf("?EM=ON") == 0) {
|
||||
if ((Config.digi.mode == 2 || Config.digi.mode == 3) && Config.loramodule.txActive && Config.loramodule.rxActive && !Config.aprs_is.active) {
|
||||
if (Config.digi.ecoMode == 0) { // Start Digipeater EcoMode
|
||||
} else if (queryQuestion.startsWith("?EM=ON")) {
|
||||
if ((digiMode == 2 || digiMode == 3) && onlyRadioActive) {
|
||||
if (digiEcoMode == 0) { // Start Digipeater EcoMode
|
||||
answer = "DigiEcoMode:ON";
|
||||
Config.digi.ecoMode = 1;
|
||||
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sent before restart.
|
||||
@@ -105,31 +109,29 @@ namespace QUERY_Utils {
|
||||
} else {
|
||||
answer = "Digipeater Mode control not possible";
|
||||
}
|
||||
} else if (queryQuestion.indexOf("?EM=?") == 0) { // Digipeater EcoMode Status
|
||||
if (Config.digi.ecoMode == 0) {
|
||||
answer = "DigiEcoMode:OFF";
|
||||
} else if (Config.digi.ecoMode == 1) {
|
||||
answer = "DigiEcoMode:ON";
|
||||
} else {
|
||||
answer = "DigiEcoMode:OFF/Only Serial Output";
|
||||
} else if (queryQuestion.startsWith("?EM=?")) { // Digipeater EcoMode Status
|
||||
switch (digiEcoMode) {
|
||||
case 0: answer = "DigiEcoMode:OFF"; break;
|
||||
case 1: answer = "DigiEcoMode:ON"; break;
|
||||
default: answer = "DigiEcoMode:OFF/Only Serial Output";
|
||||
}
|
||||
} else if (queryQuestion.indexOf("?TX=ON") == 0) {
|
||||
if (Config.loramodule.txActive) {
|
||||
} else if (queryQuestion.startsWith("?TX=ON")) {
|
||||
if (radioTxActive) {
|
||||
answer = "TX was ON";
|
||||
} else {
|
||||
Config.loramodule.txActive = true;
|
||||
answer = "TX=ON";
|
||||
}
|
||||
} else if (queryQuestion.indexOf("?TX=OFF") == 0) {
|
||||
if (!Config.loramodule.txActive) {
|
||||
} else if (queryQuestion.startsWith("?TX=OFF")) {
|
||||
if (!radioTxActive) {
|
||||
answer = "TX was OFF";
|
||||
} else {
|
||||
Config.loramodule.txActive = false;
|
||||
answer = "TX=OFF";
|
||||
}
|
||||
} else if (queryQuestion.indexOf("?TX=?") == 0) {
|
||||
answer = (Config.loramodule.txActive) ? "TX=ON" : "TX=OFF";
|
||||
} else if (queryQuestion.indexOf("?COMMIT") == 0) { // saving for next reboot
|
||||
}
|
||||
} else if (queryQuestion.startsWith("?TX=?")) {
|
||||
answer = (radioTxActive) ? "TX=ON" : "TX=OFF";
|
||||
} else if (queryQuestion.startsWith("?COMMIT")) { // saving for next reboot
|
||||
answer = "New Config Saved";
|
||||
Config.writeFile();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -51,12 +51,13 @@ namespace SLEEP_Utils {
|
||||
if (Config.digi.ecoMode == 1) {
|
||||
pinMode(RADIO_WAKEUP_PIN, INPUT);
|
||||
attachInterrupt(digitalPinToInterrupt(RADIO_WAKEUP_PIN), wakeUpLoRaPacketReceived, RISING);
|
||||
#if defined(TTGO_LORA32_V2_1) || defined(TTGO_LORA32_V2_1_915) || defined(TTGO_LORA32_T3S3_V1_2) || defined(TTGO_T_BEAM_V1_0) || defined(TTGO_T_BEAM_V1_0_915) || defined(TTGO_T_BEAM_V1_0_SX1268) || defined(TTGO_T_BEAM_V1_2) || defined(TTGO_T_BEAM_V1_2_915) || defined(TTGO_T_BEAM_V1_2_SX1262) || defined(TTGO_T_DECK_PLUS) || defined(TTGO_T_DECK_GPS) || defined(TTGO_T_Beam_S3_SUPREME_V3) || defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WP_V1) || defined(HELTEC_WS) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY) || defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V2) || defined(XIAO_ESP32S3_LORA) || defined(LIGHTGATEWAY_1_0) || defined(LIGHTGATEWAY_PLUS_1_0) || defined(TROY_LoRa_APRS) || defined(OE5HWN_MeshCom) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915) || defined(ESP32_DIY_1W_LoRa_LLCC68) || defined(ESP32_DIY_1W_LoRa_Mesh_V1_2) || defined(WEMOS_S2_MINI_DIY_LoRa) || defined(WEMOS_D1_R32_RA02) || defined(WEMOS_LOLIN32_OLED_DIY_LoRa)
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
esp_sleep_enable_ext1_wakeup(GPIO_WAKEUP_PIN, ESP_EXT1_WAKEUP_ANY_HIGH);
|
||||
#endif
|
||||
#if defined(HELTEC_HTCT62) || defined(ESP32C3_DIY_1W_LoRa) || defined(ESP32C3_DIY_1W_LoRa_915) || defined(ESP32_C3_OctopusLab_LoRa)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
esp_deep_sleep_enable_gpio_wakeup(1ULL << GPIO_WAKEUP_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
|
||||
#endif
|
||||
//#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_NRF52)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "utils.h"
|
||||
#include <vector>
|
||||
|
||||
#define SECS_TO_WAIT 3 // soon to be deleted...
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern uint32_t lastRxTime;
|
||||
@@ -40,17 +42,16 @@ std::vector<LastHeardStation> lastHeardObjects;
|
||||
struct OutputPacketBuffer {
|
||||
String packet;
|
||||
bool isBeacon;
|
||||
OutputPacketBuffer(const String& p, bool b) : packet(p), isBeacon(b) {}
|
||||
};
|
||||
std::vector<OutputPacketBuffer> outputPacketBuffer;
|
||||
|
||||
struct Packet25SegBuffer {
|
||||
uint32_t receivedTime;
|
||||
String station;
|
||||
String payload;
|
||||
uint32_t hash;
|
||||
};
|
||||
std::vector<Packet25SegBuffer> packet25SegBuffer;
|
||||
|
||||
|
||||
bool saveNewDigiEcoModeConfig = false;
|
||||
bool packetIsBeacon = false;
|
||||
|
||||
@@ -59,19 +60,18 @@ namespace STATION_Utils {
|
||||
|
||||
std::vector<String> loadCallsignList(const String& list) {
|
||||
std::vector<String> loadedList;
|
||||
int start = 0;
|
||||
int listLength = list.length();
|
||||
|
||||
String callsigns = list;
|
||||
callsigns.trim();
|
||||
while (start < listLength) {
|
||||
while (start < listLength && list[start] == ' ') start++; // avoid blank spaces
|
||||
if (start >= listLength) break;
|
||||
|
||||
while (callsigns.length() > 0) { // != ""
|
||||
int spaceIndex = callsigns.indexOf(" ");
|
||||
if (spaceIndex == -1) { // No more spaces, add the last part
|
||||
loadedList.push_back(callsigns);
|
||||
break;
|
||||
}
|
||||
loadedList.push_back(callsigns.substring(0, spaceIndex));
|
||||
callsigns = callsigns.substring(spaceIndex + 1);
|
||||
callsigns.trim(); // Trim in case of multiple spaces
|
||||
int end = start;
|
||||
while (end < listLength && list[end] != ' ') end++; // find another blank space or reach listLength
|
||||
|
||||
loadedList.emplace_back(list.substring(start, end));
|
||||
start = end + 1; // keep on searching if listLength not reached
|
||||
}
|
||||
return loadedList;
|
||||
}
|
||||
@@ -85,8 +85,9 @@ namespace STATION_Utils {
|
||||
for (size_t i = 0; i < list.size(); i++) {
|
||||
int wildcardIndex = list[i].indexOf("*");
|
||||
if (wildcardIndex >= 0) {
|
||||
String wildcard = list[i].substring(0, wildcardIndex);
|
||||
if (callsign.startsWith(wildcard)) return true;
|
||||
if (wildcardIndex >= 2 && callsign.length() >= wildcardIndex && strncmp(callsign.c_str(), list[i].c_str(), wildcardIndex) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (list[i] == callsign) return true;
|
||||
}
|
||||
@@ -127,36 +128,33 @@ namespace STATION_Utils {
|
||||
}
|
||||
|
||||
void deleteNotHeard() {
|
||||
std::vector<LastHeardStation> lastHeardStation_temp;
|
||||
for (int i = 0; i < lastHeardStations.size(); i++) {
|
||||
if (millis() - lastHeardStations[i].lastHeardTime < Config.rememberStationTime * 60 * 1000) {
|
||||
lastHeardStation_temp.push_back(lastHeardStations[i]);
|
||||
uint32_t currentTime = millis();
|
||||
uint32_t timeout = Config.rememberStationTime * 60UL * 1000UL;
|
||||
|
||||
for (int i = lastHeardStations.size() - 1; i >= 0; i--) {
|
||||
if (currentTime - lastHeardStations[i].lastHeardTime >= timeout) {
|
||||
lastHeardStations.erase(lastHeardStations.begin() + i);
|
||||
}
|
||||
}
|
||||
lastHeardStations.clear();
|
||||
for (int j = 0; j < lastHeardStation_temp.size(); j++) {
|
||||
lastHeardStations.push_back(lastHeardStation_temp[j]);
|
||||
}
|
||||
lastHeardStation_temp.clear();
|
||||
}
|
||||
|
||||
void updateLastHeard(const String& station) {
|
||||
deleteNotHeard();
|
||||
bool stationHeard = false;
|
||||
for (int i = 0; i < lastHeardStations.size(); i++) {
|
||||
uint32_t currentTime = millis();
|
||||
for (size_t i = 0; i < lastHeardStations.size(); i++) {
|
||||
if (lastHeardStations[i].station == station) {
|
||||
lastHeardStations[i].lastHeardTime = millis();
|
||||
stationHeard = true;
|
||||
break;
|
||||
lastHeardStations[i].lastHeardTime = currentTime;
|
||||
Utils::showActiveStations();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!stationHeard) lastHeardStations.emplace_back(LastHeardStation{millis(), station});
|
||||
lastHeardStations.emplace_back(LastHeardStation{currentTime, station});
|
||||
Utils::showActiveStations();
|
||||
}
|
||||
|
||||
bool wasHeard(const String& station) {
|
||||
deleteNotHeard();
|
||||
for (int i = 0; i < lastHeardStations.size(); i++) {
|
||||
for (size_t i = 0; i < lastHeardStations.size(); i++) {
|
||||
if (lastHeardStations[i].station == station) {
|
||||
Utils::println(" ---> Listened Station");
|
||||
return true;
|
||||
@@ -166,18 +164,33 @@ namespace STATION_Utils {
|
||||
return false;
|
||||
}
|
||||
|
||||
void clean25SegBuffer() {
|
||||
if (!packet25SegBuffer.empty() && (millis() - packet25SegBuffer[0].receivedTime) > 25 * 1000) packet25SegBuffer.erase(packet25SegBuffer.begin());
|
||||
}
|
||||
|
||||
bool check25SegBuffer(const String& station, const String& textMessage) {
|
||||
if (!packet25SegBuffer.empty()) {
|
||||
for (int i = 0; i < packet25SegBuffer.size(); i++) {
|
||||
if (packet25SegBuffer[i].station == station && packet25SegBuffer[i].payload == textMessage) return false;
|
||||
void clean25SegHashBuffer() {
|
||||
uint32_t currentTime = millis();
|
||||
for (int i = packet25SegBuffer.size() - 1; i >= 0; i--) {
|
||||
if ((currentTime - packet25SegBuffer[i].receivedTime) > 25 * 1000) {
|
||||
packet25SegBuffer.erase(packet25SegBuffer.begin() + i);
|
||||
}
|
||||
}
|
||||
packet25SegBuffer.emplace_back(Packet25SegBuffer{millis(), station, textMessage});
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t makeHash(const String& station, const String& payload) { // DJB2 Hash
|
||||
uint32_t h = 5381;
|
||||
for (size_t i = 0; i < station.length(); i++)
|
||||
h = ((h << 5) + h) + station[i];
|
||||
for (size_t i = 0; i < payload.length(); i++)
|
||||
h = ((h << 5) + h) + payload[i];
|
||||
return h;
|
||||
}
|
||||
|
||||
bool isIn25SegHashBuffer(const String& station, const String& textMessage) {
|
||||
clean25SegHashBuffer();
|
||||
uint32_t newHash = makeHash(station, textMessage);
|
||||
uint32_t currentTime = millis();
|
||||
for (int i = 0; i < packet25SegBuffer.size(); i++) {
|
||||
if (packet25SegBuffer[i].hash == newHash) return true;
|
||||
}
|
||||
packet25SegBuffer.push_back({currentTime, newHash});
|
||||
return false;
|
||||
}
|
||||
|
||||
void processOutputPacketBufferUltraEcoMode() {
|
||||
@@ -201,7 +214,7 @@ namespace STATION_Utils {
|
||||
}
|
||||
|
||||
void processOutputPacketBuffer() {
|
||||
int timeToWait = 3 * 1000; // 3 segs between packet Tx and also Rx ???
|
||||
int timeToWait = SECS_TO_WAIT * 1000; // 3 segs between packet Tx and also Rx ???
|
||||
uint32_t lastRx = millis() - lastRxTime;
|
||||
uint32_t lastTx = millis() - lastTxTime;
|
||||
if (outputPacketBuffer.size() > 0 && lastTx > timeToWait && lastRx > timeToWait) {
|
||||
@@ -229,11 +242,7 @@ namespace STATION_Utils {
|
||||
}
|
||||
|
||||
void addToOutputPacketBuffer(const String& packet, bool flag) {
|
||||
OutputPacketBuffer entry;
|
||||
entry.packet = packet;
|
||||
entry.isBeacon = flag;
|
||||
|
||||
outputPacketBuffer.push_back(entry);
|
||||
outputPacketBuffer.emplace_back(OutputPacketBuffer{packet, flag});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +1,30 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <WiFiUdp.h>
|
||||
#include <WiFi.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "syslog_utils.h"
|
||||
#include "gps_utils.h"
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
extern String versionDate;
|
||||
extern String versionNumber;
|
||||
|
||||
@@ -33,7 +34,7 @@ WiFiUDP udpClient;
|
||||
namespace SYSLOG_Utils {
|
||||
|
||||
void log(const uint8_t type, const String& packet, const int rssi, const float snr, const int freqError) {
|
||||
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
String syslogPacket = "<165>1 - ";
|
||||
syslogPacket.concat(Config.callsign);
|
||||
syslogPacket.concat(" CA2RXU_LoRa_iGate_");
|
||||
@@ -43,9 +44,11 @@ namespace SYSLOG_Utils {
|
||||
char signalData[35];
|
||||
snprintf(signalData, sizeof(signalData), " / %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
|
||||
|
||||
int colonIndex = packet.indexOf(":");
|
||||
char nextChar = packet[colonIndex + 1];
|
||||
String sender = packet.substring(3, packet.indexOf(">"));
|
||||
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
|
||||
@@ -58,13 +61,12 @@ namespace SYSLOG_Utils {
|
||||
if (nextChar == ':') {
|
||||
syslogPacket.concat("MESSAGE / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
|
||||
syslogPacket.concat("GPS / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" / ");
|
||||
int greaterThanIndex = packet.indexOf(">");
|
||||
if (packet.indexOf("WIDE1-1") > 10) {
|
||||
syslogPacket.concat(packet.substring(greaterThanIndex + 1, packet.indexOf(",")));
|
||||
syslogPacket.concat(" / WIDE1-1");
|
||||
@@ -87,11 +89,11 @@ namespace SYSLOG_Utils {
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(colonIndex + 2));
|
||||
} else if (packet.indexOf(":T#") >= 10 && packet.indexOf(":=/") == -1) {
|
||||
} else if (telemetryPacketIndex >= 10 && packet.indexOf(":=/") == -1) {
|
||||
syslogPacket.concat("TELEMETRY / ");
|
||||
syslogPacket.concat(sender);
|
||||
syslogPacket.concat(" ---> ");
|
||||
syslogPacket.concat(packet.substring(packet.indexOf(":T#") + 3));
|
||||
syslogPacket.concat(packet.substring(telemetryPacketIndex + 3));
|
||||
} else {
|
||||
syslogPacket.concat(packet);
|
||||
}
|
||||
@@ -139,12 +141,8 @@ namespace SYSLOG_Utils {
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (networkManager->isConnected()) {
|
||||
udpClient.begin(0);
|
||||
udpClient.beginPacket("syslog.trackiot.cc", 15243);
|
||||
String hiddenLogPacket = Config.callsign + "," + versionDate;
|
||||
udpClient.write((const uint8_t*)hiddenLogPacket.c_str(), hiddenLogPacket.length());
|
||||
udpClient.endPacket();
|
||||
if (Config.syslog.active) Serial.println("init : Syslog Server ... done! (at " + Config.syslog.server + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -29,10 +29,11 @@
|
||||
#include "display.h"
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern bool sendStartTelemetry;
|
||||
extern Configuration Config;
|
||||
|
||||
int telemetryCounter = random(1,999);
|
||||
int telemetryCounter = random(1,999);
|
||||
uint32_t telemetryEUPTime = 0;
|
||||
bool sendEUP = false; // Equations Units Parameters
|
||||
|
||||
|
||||
namespace TELEMETRY_Utils {
|
||||
@@ -68,10 +69,10 @@ namespace TELEMETRY_Utils {
|
||||
}
|
||||
|
||||
void sendBaseTelemetryPacket(const String& prefix, const std::vector<String>& values) {
|
||||
String packet = prefix + joinWithCommas(values);
|
||||
|
||||
String packet = prefix + joinWithCommas(values);
|
||||
String currentCallsign = (Config.tacticalCallsign != "") ? Config.tacticalCallsign : Config.callsign;
|
||||
if (Config.beacon.sendViaAPRSIS) {
|
||||
String baseAPRSISTelemetryPacket = APRSPacketLib::generateMessagePacket(Config.callsign, "APLRG1", "TCPIP,qAC", Config.callsign, packet);
|
||||
String baseAPRSISTelemetryPacket = APRSPacketLib::generateMessagePacket(currentCallsign, "APLRG1", "TCPIP,qAC", currentCallsign, packet);
|
||||
#ifdef HAS_A7670
|
||||
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket);
|
||||
#else
|
||||
@@ -79,7 +80,7 @@ namespace TELEMETRY_Utils {
|
||||
#endif
|
||||
delay(300);
|
||||
} else if (Config.beacon.sendViaRF) {
|
||||
String baseRFTelemetryPacket = APRSPacketLib::generateMessagePacket(Config.callsign, "APLRG1", Config.beacon.path, Config.callsign, packet);
|
||||
String baseRFTelemetryPacket = APRSPacketLib::generateMessagePacket(currentCallsign, "APLRG1", Config.beacon.path, currentCallsign, packet);
|
||||
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket);
|
||||
delay(3000);
|
||||
}
|
||||
@@ -89,7 +90,7 @@ namespace TELEMETRY_Utils {
|
||||
sendBaseTelemetryPacket("EQNS.", getEquationCoefficients());
|
||||
sendBaseTelemetryPacket("UNIT.", getUnitLabels());
|
||||
sendBaseTelemetryPacket("PARM.", getParameterNames());
|
||||
sendStartTelemetry = false;
|
||||
sendEUP = false;
|
||||
}
|
||||
|
||||
String generateEncodedTelemetryBytes(float value, bool counterBytes, byte telemetryType) {
|
||||
@@ -106,7 +107,7 @@ namespace TELEMETRY_Utils {
|
||||
case 3: tempValue = (value * 8); break; // Pressure
|
||||
default: tempValue = value; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int firstByte = tempValue / 91;
|
||||
tempValue -= firstByte * 91;
|
||||
@@ -127,4 +128,11 @@ namespace TELEMETRY_Utils {
|
||||
return telemetry;
|
||||
}
|
||||
|
||||
void checkEUPInterval() {
|
||||
if (telemetryEUPTime == 0 || millis() - telemetryEUPTime > 24UL * 60UL * 60UL * 1000UL) {
|
||||
sendEUP = true;
|
||||
telemetryEUPTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ String inputSerialBuffer = "";
|
||||
|
||||
|
||||
namespace TNC_Utils {
|
||||
|
||||
|
||||
void setup() {
|
||||
if (Config.tnc.enableServer && Config.digi.ecoMode == 0) {
|
||||
tncServer.stop();
|
||||
|
||||
185
src/utils.cpp
185
src/utils.cpp
@@ -1,26 +1,26 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <TinyGPS++.h>
|
||||
#include <WiFi.h>
|
||||
#include "telemetry_utils.h"
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "station_utils.h"
|
||||
#include "battery_utils.h"
|
||||
#include "aprs_is_utils.h"
|
||||
@@ -34,8 +34,10 @@
|
||||
#include "display.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define DAY_MS (24UL * 60UL * 60UL * 1000UL)
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
extern TinyGPSPlus gps;
|
||||
extern String versionDate;
|
||||
extern String firstLine;
|
||||
@@ -51,20 +53,21 @@ extern int rssi;
|
||||
extern float snr;
|
||||
extern int freqError;
|
||||
extern String distance;
|
||||
extern bool WiFiConnected;
|
||||
extern int wxModuleType;
|
||||
extern bool backUpDigiMode;
|
||||
extern bool backupDigiMode;
|
||||
extern bool shouldSleepLowVoltage;
|
||||
extern bool transmitFlag;
|
||||
extern bool passcodeValid;
|
||||
extern bool sendEUP; // Equations Units Parameters
|
||||
|
||||
extern std::vector<LastHeardStation> lastHeardStations;
|
||||
|
||||
bool statusAfterBoot = true;
|
||||
bool sendStartTelemetry = true;
|
||||
bool beaconUpdate = false;
|
||||
uint32_t lastBeaconTx = 0;
|
||||
uint32_t lastScreenOn = millis();
|
||||
bool statusUpdate = true;
|
||||
bool beaconUpdate = false;
|
||||
uint32_t lastBeaconTx = 0;
|
||||
uint32_t lastScreenOn = millis();
|
||||
uint32_t lastStatusTx = 0;
|
||||
bool stationCallsignIsValid = false;
|
||||
String beaconPacket;
|
||||
String secondaryBeaconPacket;
|
||||
|
||||
@@ -72,33 +75,43 @@ String secondaryBeaconPacket;
|
||||
namespace Utils {
|
||||
|
||||
void processStatus() {
|
||||
String status = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
|
||||
bool sendOverAPRSIS = Config.beacon.sendViaAPRSIS && Config.aprs_is.active && networkManager->isConnected();
|
||||
bool sendOverRF = !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF;
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED && Config.aprs_is.active && Config.beacon.sendViaAPRSIS) {
|
||||
delay(1000);
|
||||
status.concat(",qAC:>");
|
||||
status.concat(Config.beacon.statusPacket);
|
||||
APRS_IS_Utils::upload(status);
|
||||
SYSLOG_Utils::log(2, status, 0, 0.0, 0); // APRSIS TX
|
||||
statusAfterBoot = false;
|
||||
if (!sendOverAPRSIS && !sendOverRF) {
|
||||
statusUpdate = false;
|
||||
return;
|
||||
}
|
||||
if (statusAfterBoot && !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF) {
|
||||
status.concat(":>");
|
||||
status.concat(Config.beacon.statusPacket);
|
||||
STATION_Utils::addToOutputPacketBuffer(status, true); // treated also as beacon on Tx Freq
|
||||
statusAfterBoot = false;
|
||||
|
||||
String statusPacket = APRSPacketLib::generateBasePacket(Config.callsign, "APLRG1", Config.beacon.path);
|
||||
statusPacket += sendOverAPRSIS ? ",qAC:>" : ":>";
|
||||
statusPacket += Config.beacon.statusPacket;
|
||||
|
||||
if (sendOverAPRSIS) {
|
||||
APRS_IS_Utils::upload(statusPacket);
|
||||
SYSLOG_Utils::log(2, statusPacket, 0, 0.0, 0); // APRSIS TX
|
||||
} else {
|
||||
STATION_Utils::addToOutputPacketBuffer(statusPacket, true); // treated also as beacon on Tx Freq
|
||||
}
|
||||
statusUpdate = false;
|
||||
lastStatusTx = millis();
|
||||
}
|
||||
|
||||
void checkStatusInterval() {
|
||||
if (lastStatusTx == 0 || millis() - lastStatusTx > DAY_MS) statusUpdate = true;
|
||||
}
|
||||
|
||||
String getLocalIP() {
|
||||
if (Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
|
||||
return "** WiFi AP Killed **";
|
||||
} else if (!WiFiConnected) {
|
||||
return "IP : 192.168.4.1";
|
||||
} else if (backUpDigiMode) {
|
||||
} else if (networkManager->isEthernetConnected()) {
|
||||
return "LAN: " + networkManager->getEthernetIP().toString();
|
||||
} else if (!networkManager->isWiFiConnected() && networkManager->isWifiAPActive()) {
|
||||
return "IP : " + networkManager->getWiFiAPIP().toString();
|
||||
} else if (backupDigiMode) {
|
||||
return "- BACKUP DIGI MODE -";
|
||||
} else {
|
||||
return "IP : " + String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]);
|
||||
return "IP : " + networkManager->getWiFiIP().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +133,11 @@ namespace Utils {
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,LOW);
|
||||
#endif
|
||||
firstLine = Config.callsign;
|
||||
if (Config.tacticalCallsign != "") {
|
||||
firstLine = Config.tacticalCallsign;
|
||||
} else {
|
||||
firstLine = Config.callsign;
|
||||
}
|
||||
seventhLine = " listening...";
|
||||
}
|
||||
|
||||
@@ -146,9 +163,10 @@ namespace Utils {
|
||||
if (beaconUpdate) {
|
||||
if (!Config.display.alwaysOn && Config.display.timeout != 0) displayToggle(true);
|
||||
|
||||
if (sendStartTelemetry &&
|
||||
TELEMETRY_Utils::checkEUPInterval();
|
||||
if (sendEUP &&
|
||||
Config.battery.sendVoltageAsTelemetry &&
|
||||
!Config.wxsensor.active &&
|
||||
!Config.wxsensor.active &&
|
||||
(Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage) &&
|
||||
(lastBeaconTx > 0)) {
|
||||
TELEMETRY_Utils::sendEquationsUnitsParameters();
|
||||
@@ -187,6 +205,12 @@ namespace Utils {
|
||||
}
|
||||
beaconPacket += Config.beacon.comment;
|
||||
secondaryBeaconPacket += Config.beacon.comment;
|
||||
if (stationCallsignIsValid && Config.tacticalCallsign != "") {
|
||||
beaconPacket += " de ";
|
||||
beaconPacket += Config.callsign;
|
||||
secondaryBeaconPacket += " de ";
|
||||
secondaryBeaconPacket += Config.callsign;
|
||||
}
|
||||
|
||||
#if defined(BATTERY_PIN) || defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||
if (Config.battery.sendInternalVoltage || Config.battery.monitorInternalVoltage) {
|
||||
@@ -227,7 +251,7 @@ namespace Utils {
|
||||
if (Config.battery.sendExternalVoltage) {
|
||||
char externalVoltageInfo[10]; // "xx.xxV\0" (max 7 chars)
|
||||
snprintf(externalVoltageInfo, sizeof(externalVoltageInfo), "%.2fV", externalVoltage);
|
||||
|
||||
|
||||
char sixthLineBuffer[25]; // Ensure enough space
|
||||
snprintf(sixthLineBuffer, sizeof(sixthLineBuffer), " (Ext V=%s)", externalVoltageInfo);
|
||||
sixthLine = sixthLineBuffer;
|
||||
@@ -248,7 +272,7 @@ namespace Utils {
|
||||
secondaryBeaconPacket += encodedTelemetry;
|
||||
}
|
||||
|
||||
if (Config.beacon.sendViaAPRSIS && Config.aprs_is.active && passcodeValid && !backUpDigiMode) {
|
||||
if (Config.beacon.sendViaAPRSIS && Config.aprs_is.active && passcodeValid && !backupDigiMode) {
|
||||
Utils::println("-- Sending Beacon to APRSIS --");
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING IGATE BEACON", 0);
|
||||
seventhLine = " listening...";
|
||||
@@ -260,7 +284,7 @@ namespace Utils {
|
||||
if (Config.syslog.logBeaconOverTCPIP) SYSLOG_Utils::log(1, "tcp" + beaconPacket, 0, 0.0, 0); // APRSIS TX
|
||||
}
|
||||
|
||||
if (Config.beacon.sendViaRF || backUpDigiMode) {
|
||||
if (Config.beacon.sendViaRF || backupDigiMode) {
|
||||
Utils::println("-- Sending Beacon to RF --");
|
||||
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING DIGI BEACON", 0);
|
||||
seventhLine = " listening...";
|
||||
@@ -272,9 +296,8 @@ namespace Utils {
|
||||
beaconUpdate = false;
|
||||
}
|
||||
|
||||
if (statusAfterBoot && Config.beacon.statusActive && !Config.beacon.statusPacket.isEmpty()) {
|
||||
processStatus();
|
||||
}
|
||||
checkStatusInterval();
|
||||
if (statusUpdate && Config.beacon.statusActive && !Config.beacon.statusPacket.isEmpty()) processStatus();
|
||||
}
|
||||
|
||||
void checkDisplayInterval() {
|
||||
@@ -296,7 +319,6 @@ namespace Utils {
|
||||
}
|
||||
|
||||
void typeOfPacket(const String& packet, const uint8_t packetType) {
|
||||
String sender = packet.substring(0,packet.indexOf(">"));
|
||||
switch (packetType) {
|
||||
case 0: // LoRa-APRS
|
||||
fifthLine = "LoRa Rx ----> APRS-IS";
|
||||
@@ -312,6 +334,7 @@ namespace Utils {
|
||||
int firstColonIndex = packet.indexOf(":");
|
||||
char nextChar = packet[firstColonIndex + 1];
|
||||
|
||||
String sender = packet.substring(0,packet.indexOf(">"));
|
||||
for (int i = sender.length(); i < 9; i++) {
|
||||
sender += " ";
|
||||
}
|
||||
@@ -387,9 +410,9 @@ namespace Utils {
|
||||
if (mode == 1) { // low voltage detected after a while
|
||||
displayToggle(false);
|
||||
}
|
||||
#ifdef VEXT_CTRL
|
||||
#ifdef VEXT_CTRL_PIN
|
||||
#ifndef HELTEC_WSL_V3
|
||||
digitalWrite(VEXT_CTRL, LOW);
|
||||
digitalWrite(VEXT_CTRL_PIN, LOW);
|
||||
#endif
|
||||
#endif
|
||||
LoRa_Utils::sleepRadio();
|
||||
@@ -399,45 +422,55 @@ namespace Utils {
|
||||
}
|
||||
}
|
||||
|
||||
bool checkValidCallsign(const String& callsign) {
|
||||
bool callsignIsValid(const String& callsign) {
|
||||
if (callsign == "WLNK-1") return true;
|
||||
|
||||
String cleanCallsign;
|
||||
if (callsign.indexOf("-") > 0) { // SSID Validation
|
||||
cleanCallsign = callsign.substring(0, callsign.indexOf("-"));
|
||||
String ssid = callsign.substring(callsign.indexOf("-") + 1);
|
||||
if (ssid.indexOf("-") != -1 || ssid.length() > 2) return false;
|
||||
if (ssid.length() == 2 && ssid[0] == '0') return false;
|
||||
for (int i = 0; i < ssid.length(); i++) {
|
||||
if (!isAlphaNumeric(ssid[i])) return false;
|
||||
int totalCallsignLength = callsign.length();
|
||||
if (totalCallsignLength < 4) return false;
|
||||
|
||||
int hyphenIndex = callsign.indexOf("-");
|
||||
int baseCallsignLength = (hyphenIndex > 0) ? hyphenIndex : totalCallsignLength;
|
||||
|
||||
if (hyphenIndex > 0) { // SSID Validation
|
||||
if (hyphenIndex < 4) return false; // base Callsign must have at least 4 characters
|
||||
int ssidStart = hyphenIndex + 1;
|
||||
int ssidLength = totalCallsignLength - ssidStart;
|
||||
if (ssidLength == 0 || ssidLength > 2) return false;
|
||||
if (callsign.indexOf('-', ssidStart) != -1) return false; // avoid another "-" in ssid
|
||||
if (ssidLength == 2 && callsign[ssidStart] == '0') return false; // ssid can't start with "0"
|
||||
for (int i = ssidStart; i < totalCallsignLength; i++) {
|
||||
if (!isDigit(callsign[i])) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (baseCallsignLength < 4 || baseCallsignLength > 6) return false;
|
||||
|
||||
bool padded = false; // Callsigns with 4 characters like A0AA are padded into 5 characters for further analisis : A0AA --> _A0AA
|
||||
if (baseCallsignLength == 4 && isAlpha(callsign[0]) && isDigit(callsign[1]) && isAlpha(callsign[2]) && isAlpha(callsign[3])) padded = true;
|
||||
char c0, c1, c2, c3;
|
||||
if (padded) {
|
||||
c0 = ' ';
|
||||
c1 = callsign[0];
|
||||
c2 = callsign[1];
|
||||
c3 = callsign[2];
|
||||
} else {
|
||||
cleanCallsign = callsign;
|
||||
c0 = callsign[0];
|
||||
c1 = callsign[1];
|
||||
c2 = callsign[2];
|
||||
c3 = callsign[3];
|
||||
}
|
||||
if (!isDigit(c2) || !isAlpha(c3)) { // __0A__ must be validated
|
||||
if (c0 != 'R' && !isDigit(c1) && !isAlpha(c2)) return false; // to accepto R0A___
|
||||
}
|
||||
|
||||
if (cleanCallsign.length() < 4 || cleanCallsign.length() > 6) return false;
|
||||
bool isValid =
|
||||
((isAlphaNumeric(c0) || c0 == ' ') && isAlpha(c1)) || // AA0A (+A+A) + _A0AA (+A) + 0A0A (+A+A)
|
||||
(isAlpha(c0) && isDigit(c1)) || // A00A (+A+A)
|
||||
(c0 == 'R' && baseCallsignLength == 6 && isDigit(c1) && isAlpha(c2) && isAlpha(c3) && isAlpha(callsign[4])); // R0AA (+A+A)
|
||||
if (!isValid) return false; // also 00__ avoided
|
||||
|
||||
if (cleanCallsign.length() < 6 && isAlpha(cleanCallsign[0]) && isDigit(cleanCallsign[1]) && isAlpha(cleanCallsign[2]) && isAlpha(cleanCallsign[3]) ) {
|
||||
cleanCallsign = " " + cleanCallsign; // A0AA --> _A0AA
|
||||
}
|
||||
|
||||
if (!isDigit(cleanCallsign[2]) || !isAlpha(cleanCallsign[3])) { // __0A__ must be validated
|
||||
if (cleanCallsign[0] != 'R' && !isDigit(cleanCallsign[1]) && !isAlpha(cleanCallsign[2])) return false; // to accepto R0A___
|
||||
}
|
||||
|
||||
bool isValid = false;
|
||||
if ((isAlphaNumeric(cleanCallsign[0]) || cleanCallsign[0] == ' ') && isAlpha(cleanCallsign[1])) {
|
||||
isValid = true; // AA0A (+A+A) + _A0AA (+A) + 0A0A (+A+A)
|
||||
} else if (isAlpha(cleanCallsign[0]) && isDigit(cleanCallsign[1])) {
|
||||
isValid = true; // A00A (+A+A)
|
||||
} else if (cleanCallsign[0] == 'R' && cleanCallsign.length() == 6 && isDigit(cleanCallsign[1]) && isAlpha(cleanCallsign[2]) && isAlpha(cleanCallsign[3]) && isAlpha(cleanCallsign[4])) {
|
||||
isValid = true; // R0AA (+A+A)
|
||||
}
|
||||
if (!isValid) return false; // also 00__ avoided
|
||||
|
||||
if (cleanCallsign.length() > 4) { // to validate ____AA
|
||||
for (int i = 5; i <= cleanCallsign.length(); i++) {
|
||||
if (!isAlpha(cleanCallsign[i - 1])) return false;
|
||||
if (baseCallsignLength > 4 ) { // to validate ____AA
|
||||
for (int i = 4; i < baseCallsignLength; i++) {
|
||||
if (!isAlpha(callsign[i])) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -450,4 +483,4 @@ namespace Utils {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -88,7 +88,7 @@ namespace WEB_Utils {
|
||||
return request->requestAuthentication();
|
||||
|
||||
File file = SPIFFS.open("/igate_conf.json");
|
||||
|
||||
|
||||
String fileContent;
|
||||
while(file.available()){
|
||||
fileContent += String((char)file.read());
|
||||
@@ -160,7 +160,8 @@ namespace WEB_Utils {
|
||||
Config.startupDelay = getParamIntSafe("startupDelay", Config.startupDelay);
|
||||
|
||||
Config.callsign = getParamStringSafe("callsign", Config.callsign);
|
||||
|
||||
Config.tacticalCallsign = getParamStringSafe("tacticalCallsign", Config.tacticalCallsign);
|
||||
Config.wifiAutoAP.enabled = request->hasParam("wifi.autoAP.enabled", true);
|
||||
Config.wifiAutoAP.password = getParamStringSafe("wifi.autoAP.password", Config.wifiAutoAP.password);
|
||||
Config.wifiAutoAP.timeout = getParamIntSafe("wifi.autoAP.timeout", Config.wifiAutoAP.timeout);
|
||||
|
||||
@@ -199,7 +200,7 @@ namespace WEB_Utils {
|
||||
|
||||
Config.digi.mode = getParamIntSafe("digi.mode", Config.digi.mode);
|
||||
Config.digi.ecoMode = getParamIntSafe("digi.ecoMode", Config.digi.ecoMode);
|
||||
|
||||
Config.digi.backupDigiMode = request->hasParam("digi.backupDigiMode", true);
|
||||
|
||||
Config.loramodule.rxActive = request->hasParam("lora.rxActive", true);
|
||||
Config.loramodule.rxFreq = getParamIntSafe("lora.rxFreq", Config.loramodule.rxFreq);
|
||||
@@ -213,14 +214,12 @@ namespace WEB_Utils {
|
||||
Config.loramodule.txSignalBandwidth = getParamIntSafe("lora.txSignalBandwidth", Config.loramodule.txSignalBandwidth);
|
||||
Config.loramodule.power = getParamIntSafe("lora.power", Config.loramodule.power);
|
||||
|
||||
|
||||
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
|
||||
if (!Config.display.alwaysOn) {
|
||||
Config.display.timeout = getParamIntSafe("display.timeout", Config.display.timeout);
|
||||
}
|
||||
Config.display.turn180 = request->hasParam("display.turn180", true);
|
||||
|
||||
|
||||
Config.battery.sendInternalVoltage = request->hasParam("battery.sendInternalVoltage", true);
|
||||
Config.battery.monitorInternalVoltage = request->hasParam("battery.monitorInternalVoltage", true);
|
||||
if (Config.battery.monitorInternalVoltage) {
|
||||
@@ -242,7 +241,6 @@ namespace WEB_Utils {
|
||||
}
|
||||
Config.battery.sendVoltageAsTelemetry = request->hasParam("battery.sendVoltageAsTelemetry", true);
|
||||
|
||||
|
||||
Config.wxsensor.active = request->hasParam("wxsensor.active", true);
|
||||
if (Config.wxsensor.active) {
|
||||
Config.wxsensor.heightCorrection = getParamIntSafe("wxsensor.heightCorrection", Config.wxsensor.heightCorrection);
|
||||
@@ -250,7 +248,6 @@ namespace WEB_Utils {
|
||||
Config.beacon.symbol = "_";
|
||||
}
|
||||
|
||||
|
||||
Config.syslog.active = request->hasParam("syslog.active", true);
|
||||
if (Config.syslog.active) {
|
||||
Config.syslog.server = getParamStringSafe("syslog.server", Config.syslog.server);
|
||||
@@ -258,13 +255,11 @@ namespace WEB_Utils {
|
||||
Config.syslog.logBeaconOverTCPIP = request->hasParam("syslog.logBeaconOverTCPIP", true);
|
||||
}
|
||||
|
||||
|
||||
Config.tnc.enableServer = request->hasParam("tnc.enableServer", true);
|
||||
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.mqtt.active = request->hasParam("mqtt.active", true);
|
||||
if (Config.mqtt.active) {
|
||||
Config.mqtt.server = getParamStringSafe("mqtt.server", Config.mqtt.server);
|
||||
@@ -275,7 +270,6 @@ namespace WEB_Utils {
|
||||
Config.mqtt.beaconOverMqtt = request->hasParam("mqtt.beaconOverMqtt", true);
|
||||
}
|
||||
|
||||
|
||||
Config.rebootMode = request->hasParam("other.rebootMode", true);
|
||||
if (Config.rebootMode) {
|
||||
Config.rebootModeTime = getParamIntSafe("other.rebootModeTime", Config.rebootModeTime);
|
||||
@@ -298,8 +292,6 @@ namespace WEB_Utils {
|
||||
|
||||
Config.rememberStationTime = getParamIntSafe("other.rememberStationTime", Config.rememberStationTime);
|
||||
|
||||
Config.backupDigiMode = request->hasParam("other.backupDigiMode", true);
|
||||
|
||||
bool saveSuccess = Config.writeFile();
|
||||
|
||||
if (saveSuccess) {
|
||||
@@ -307,7 +299,7 @@ namespace WEB_Utils {
|
||||
AsyncWebServerResponse *response = request->beginResponse(302, "text/html", "");
|
||||
response->addHeader("Location", "/?success=1");
|
||||
request->send(response);
|
||||
|
||||
|
||||
displayToggle(false);
|
||||
delay(500);
|
||||
ESP.restart();
|
||||
@@ -317,7 +309,7 @@ namespace WEB_Utils {
|
||||
errorPage += "<h1>Configuration Error:</h1>";
|
||||
errorPage += "<p>Couldn't save new configuration. Please try again.</p>";
|
||||
errorPage += "<a href='/'>Back</a></body></html>";
|
||||
|
||||
|
||||
AsyncWebServerResponse *response = request->beginResponse(500, "text/html", errorPage);
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <WiFi.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
#include "board_pinout.h"
|
||||
#include "wifi_utils.h"
|
||||
#include "display.h"
|
||||
@@ -25,148 +26,103 @@
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
|
||||
extern uint8_t myWiFiAPIndex;
|
||||
extern int myWiFiAPSize;
|
||||
extern WiFi_AP *currentWiFi;
|
||||
extern bool backUpDigiMode;
|
||||
extern bool backupDigiMode;
|
||||
extern uint32_t lastServerCheck;
|
||||
|
||||
bool WiFiConnected = false;
|
||||
uint32_t WiFiAutoAPTime = millis();
|
||||
bool WiFiAutoAPStarted = false;
|
||||
uint32_t previousWiFiMillis = 0;
|
||||
uint8_t wifiCounter = 0;
|
||||
uint32_t lastBackupDigiTime = millis();
|
||||
uint32_t lastWiFiCheck = 0;
|
||||
|
||||
|
||||
namespace WIFI_Utils {
|
||||
|
||||
void checkWiFi() {
|
||||
if (Config.digi.ecoMode == 0) {
|
||||
if (backUpDigiMode) {
|
||||
uint32_t WiFiCheck = millis() - lastBackupDigiTime;
|
||||
if (WiFi.status() != WL_CONNECTED && WiFiCheck >= 15 * 60 * 1000) {
|
||||
Serial.println("*** Stopping BackUp Digi Mode ***");
|
||||
backUpDigiMode = false;
|
||||
wifiCounter = 0;
|
||||
} else if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.println("*** WiFi Reconnect Success (Stopping Backup Digi Mode) ***");
|
||||
backUpDigiMode = false;
|
||||
wifiCounter = 0;
|
||||
}
|
||||
if (Config.digi.ecoMode != 0) return;
|
||||
|
||||
if (!networkManager->hasWiFiNetworks()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t currentTime = millis();
|
||||
|
||||
if (backupDigiMode) {
|
||||
if (!networkManager->isWiFiConnected() && ((currentTime - lastBackupDigiTime) >= 15 * 60 * 1000)) {
|
||||
Serial.println("*** Stopping BackUp Digi Mode ***");
|
||||
backupDigiMode = false;
|
||||
wifiCounter = 0;
|
||||
} else if (networkManager->isWiFiConnected()) {
|
||||
Serial.println("*** WiFi Reconnect Success (Stopping Backup Digi Mode) ***");
|
||||
backupDigiMode = false;
|
||||
wifiCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!backUpDigiMode && (WiFi.status() != WL_CONNECTED) && ((millis() - previousWiFiMillis) >= 30 * 1000) && !WiFiAutoAPStarted) {
|
||||
Serial.print(millis());
|
||||
Serial.println("Reconnecting to WiFi...");
|
||||
WiFi.disconnect();
|
||||
WIFI_Utils::startWiFi();
|
||||
previousWiFiMillis = millis();
|
||||
|
||||
if (Config.backupDigiMode) {
|
||||
wifiCounter++;
|
||||
if (!backupDigiMode && ((currentTime - lastWiFiCheck) >= 30 * 1000) && !networkManager->isWifiAPActive()) {
|
||||
lastWiFiCheck = currentTime;
|
||||
if (networkManager->isWiFiConnected()) {
|
||||
if (Config.digi.backupDigiMode && (currentTime - lastServerCheck > 30 * 1000)) {
|
||||
Serial.println("*** Server Connection LOST → Backup Digi Mode ***");
|
||||
backupDigiMode = true;
|
||||
lastBackupDigiTime = currentTime;
|
||||
}
|
||||
} else {
|
||||
Serial.println("Reconnecting to WiFi...");
|
||||
WIFI_Utils::startWiFi();
|
||||
|
||||
if (Config.digi.backupDigiMode) wifiCounter++;
|
||||
if (wifiCounter >= 2) {
|
||||
Serial.println("*** Starting BackUp Digi Mode ***");
|
||||
backUpDigiMode = true;
|
||||
lastBackupDigiTime = millis();
|
||||
backupDigiMode = true;
|
||||
lastBackupDigiTime = currentTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startAutoAP() {
|
||||
WiFi.mode(WIFI_MODE_NULL);
|
||||
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAP(Config.callsign + "-AP", Config.wifiAutoAP.password);
|
||||
|
||||
WiFiAutoAPTime = millis();
|
||||
WiFiAutoAPStarted = true;
|
||||
displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000);
|
||||
networkManager->setupAP(Config.callsign + "-AP", Config.wifiAutoAP.password);
|
||||
}
|
||||
|
||||
void startWiFi() {
|
||||
bool startAP = false;
|
||||
if (currentWiFi->ssid == "") {
|
||||
startAP = true;
|
||||
} else {
|
||||
uint8_t wifiCounter = 0;
|
||||
String hostName = "iGATE-" + Config.callsign;
|
||||
WiFi.setHostname(hostName.c_str());
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.disconnect();
|
||||
delay(500);
|
||||
unsigned long start = millis();
|
||||
displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0);
|
||||
Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.println("' ...");
|
||||
WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str());
|
||||
while (WiFi.status() != WL_CONNECTED && wifiCounter<myWiFiAPSize) {
|
||||
delay(500);
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,HIGH);
|
||||
#endif
|
||||
Serial.print('.');
|
||||
delay(500);
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,LOW);
|
||||
#endif
|
||||
if ((millis() - start) > 10000){
|
||||
delay(1000);
|
||||
if(myWiFiAPIndex >= (myWiFiAPSize - 1)) {
|
||||
myWiFiAPIndex = 0;
|
||||
wifiCounter++;
|
||||
} else {
|
||||
myWiFiAPIndex++;
|
||||
}
|
||||
wifiCounter++;
|
||||
currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
|
||||
start = millis();
|
||||
Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.println("' ...");
|
||||
displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0);
|
||||
WiFi.disconnect();
|
||||
WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str());
|
||||
}
|
||||
networkManager->clearWiFiNetworks();
|
||||
for (size_t i = 0; i < Config.wifiAPs.size(); i++) {
|
||||
const WiFi_AP& wifiAP = Config.wifiAPs[i];
|
||||
if (wifiAP.ssid.isEmpty()) continue;
|
||||
networkManager->addWiFiNetwork(wifiAP.ssid, wifiAP.password);
|
||||
}
|
||||
|
||||
if (!networkManager->hasWiFiNetworks()) {
|
||||
Serial.println("WiFi SSID not set!");
|
||||
if (Config.wifiAutoAP.enabled) {
|
||||
Serial.println("Starting AP fallback...");
|
||||
startAutoAP();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
displayShow("", "Connecting to WiFi:", "", " loading ...", 0);
|
||||
networkManager->connectWiFi();
|
||||
|
||||
#ifdef INTERNAL_LED_PIN
|
||||
digitalWrite(INTERNAL_LED_PIN,LOW);
|
||||
digitalWrite(INTERNAL_LED_PIN, LOW);
|
||||
#endif
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
Serial.print("\nConnected as ");
|
||||
Serial.print(WiFi.localIP());
|
||||
if (networkManager->isWiFiConnected()) {
|
||||
Serial.print("[WiFi] Connected as ");
|
||||
Serial.print(networkManager->getWiFiIP());
|
||||
Serial.print(" / MAC Address: ");
|
||||
Serial.println(WiFi.macAddress());
|
||||
Serial.println(networkManager->getWiFimacAddress());
|
||||
displayShow("", " Connected!!", "" , " loading ...", 1000);
|
||||
} else if (WiFi.status() != WL_CONNECTED) {
|
||||
startAP = true;
|
||||
|
||||
Serial.println("\nNot connected to WiFi! Starting Auto AP");
|
||||
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000);
|
||||
}
|
||||
WiFiConnected = !startAP;
|
||||
if (startAP) {
|
||||
Serial.println("\nNot connected to WiFi! Starting Auto AP");
|
||||
displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000);
|
||||
|
||||
startAutoAP();
|
||||
}
|
||||
}
|
||||
|
||||
void checkAutoAPTimeout() {
|
||||
if (WiFiAutoAPStarted && Config.wifiAutoAP.timeout > 0) {
|
||||
if (WiFi.softAPgetStationNum() > 0) {
|
||||
WiFiAutoAPTime = 0;
|
||||
} else {
|
||||
Serial.println("[WiFi] Not connected to WiFi!");
|
||||
if (Config.wifiAutoAP.enabled) {
|
||||
Serial.println("Starting AP fallback...");
|
||||
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000);
|
||||
startAutoAP();
|
||||
} else {
|
||||
if (WiFiAutoAPTime == 0) {
|
||||
WiFiAutoAPTime = millis();
|
||||
} else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.timeout * 60 * 1000) {
|
||||
Serial.println("Stopping auto AP");
|
||||
|
||||
WiFiAutoAPStarted = false;
|
||||
WiFi.softAPdisconnect(true);
|
||||
|
||||
Serial.println("Auto AP stopped (timeout)");
|
||||
}
|
||||
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,4 +132,4 @@ namespace WIFI_Utils {
|
||||
btStop();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -42,7 +42,7 @@ float newHum, newTemp, newPress, newGas;
|
||||
|
||||
|
||||
Adafruit_BME280 bme280;
|
||||
Adafruit_AHTX0 aht20;
|
||||
Adafruit_AHTX0 aht20;
|
||||
#if defined(HELTEC_V3) || defined(HELTEC_V3_2)
|
||||
Adafruit_BMP280 bmp280(&Wire1);
|
||||
Adafruit_Si7021 si7021 = Adafruit_Si7021();
|
||||
@@ -61,9 +61,9 @@ namespace WX_Utils {
|
||||
void getWxModuleAddres() {
|
||||
uint8_t err, addr;
|
||||
for(addr = 1; addr < 0x7F; addr++) {
|
||||
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
|
||||
Wire1.beginTransmission(addr);
|
||||
err = Wire1.endTransmission();
|
||||
#ifdef SENSOR_I2C_BUS
|
||||
SENSOR_I2C_BUS.beginTransmission(addr);
|
||||
err = SENSOR_I2C_BUS.endTransmission();
|
||||
#else
|
||||
Wire.beginTransmission(addr);
|
||||
#ifdef LIGHTGATEWAY_PLUS_1_0
|
||||
@@ -161,7 +161,7 @@ namespace WX_Utils {
|
||||
Adafruit_BMP280::SAMPLING_X1,
|
||||
Adafruit_BMP280::SAMPLING_X1,
|
||||
Adafruit_BMP280::FILTER_OFF
|
||||
);
|
||||
);
|
||||
Serial.println("BMP280 Module init done!");
|
||||
break;
|
||||
case 3:
|
||||
@@ -306,7 +306,7 @@ namespace WX_Utils {
|
||||
humStr = "..";
|
||||
}
|
||||
|
||||
String presStr = (wxModuleType == 4 || wxModuleType == 5)
|
||||
String presStr = (wxModuleType == 4 || wxModuleType == 5)
|
||||
? "....."
|
||||
: generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR);
|
||||
|
||||
|
||||
63
variants/ESP32_9M2IBR_1W_LoRa_GPS/board_pinout.h
Normal file
63
variants/ESP32_9M2IBR_1W_LoRa_GPS/board_pinout.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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_SX1268
|
||||
#define HAS_1W_LORA
|
||||
#define HAS_TCXO
|
||||
#define RADIO_SCLK_PIN 18
|
||||
#define RADIO_MISO_PIN 19
|
||||
#define RADIO_MOSI_PIN 23
|
||||
#define RADIO_CS_PIN 5
|
||||
#define RADIO_RST_PIN 27
|
||||
#define RADIO_DIO1_PIN 12
|
||||
#define RADIO_BUSY_PIN 14
|
||||
#define RADIO_RXEN 32
|
||||
#define RADIO_TXEN 25
|
||||
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_12
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
#define HAS_SH1106
|
||||
|
||||
#undef OLED_SDA
|
||||
#undef OLED_SCL
|
||||
#undef OLED_RST
|
||||
|
||||
#define OLED_SDA 21
|
||||
#define OLED_SCL 22
|
||||
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
||||
|
||||
// GPS
|
||||
#define HAS_GPS
|
||||
#define GPS_BAUDRATE 9600
|
||||
#define GPS_RX 17
|
||||
#define GPS_TX 16
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 2
|
||||
#define BATTERY_PIN 35
|
||||
|
||||
#endif
|
||||
12
variants/ESP32_9M2IBR_1W_LoRa_GPS/platformio.ini
Normal file
12
variants/ESP32_9M2IBR_1W_LoRa_GPS/platformio.ini
Normal file
@@ -0,0 +1,12 @@
|
||||
[env:ESP32_9M2IBR_1W_LoRa_GPS]
|
||||
board = esp32dev
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-D RADIOLIB_EXCLUDE_LR11X0=1
|
||||
-D RADIOLIB_EXCLUDE_SX127X=1
|
||||
-D RADIOLIB_EXCLUDE_SX128X=1
|
||||
-D ESP32_9M2IBR_1W_LoRa_GPS
|
||||
lib_deps =
|
||||
${common.lib_deps}
|
||||
${common.display_libs}
|
||||
adafruit/Adafruit SH110X @ 2.1.10
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -45,5 +45,5 @@
|
||||
#define OLED_SDA 0
|
||||
#define OLED_SCL 1
|
||||
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
|
||||
|
||||
#undef OLED_SDA
|
||||
#undef OLED_SCL
|
||||
#undef OLED_RST
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -44,8 +44,8 @@
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 13 // 13 for V1.1 and 12 for V1.0
|
||||
#define BATTERY_PIN 35
|
||||
|
||||
#define BATTERY_PIN 35
|
||||
|
||||
#define HAS_A7670
|
||||
#define A7670_PWR_PIN 4
|
||||
#define A7670_ResetPin 5
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -31,7 +31,7 @@
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
|
||||
// Display
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
|
||||
#undef OLED_SDA
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -31,7 +31,7 @@
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_38
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire
|
||||
#define BOARD_I2C_SDA 11
|
||||
#define BOARD_I2C_SCL 12
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -39,8 +39,8 @@
|
||||
#define INTERNAL_LED_PIN 48
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
#define OLED_SDA 5
|
||||
#define OLED_SCL 6
|
||||
#define SENSOR_I2C_BUS Wire
|
||||
#define BOARD_I2C_SDA 5
|
||||
#define BOARD_I2C_SCL 6
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -48,6 +48,8 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 25
|
||||
#define BATTERY_PIN 37
|
||||
#define ADC_CTRL 21
|
||||
|
||||
|
||||
#define ADC_CTRL_PIN 21
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
55
variants/heltec-lora32-v2_915/board_pinout.h
Normal file
55
variants/heltec-lora32-v2_915/board_pinout.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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_SX1276
|
||||
#define RADIO_SCLK_PIN 5
|
||||
#define RADIO_MISO_PIN 19
|
||||
#define RADIO_MOSI_PIN 27
|
||||
#define RADIO_CS_PIN 18
|
||||
#define RADIO_RST_PIN 14
|
||||
#define RADIO_BUSY_PIN 26
|
||||
#define RADIO_WAKEUP_PIN RADIO_BUSY_PIN
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_26
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
|
||||
#undef OLED_SDA
|
||||
#undef OLED_SCL
|
||||
#undef OLED_RST
|
||||
|
||||
#define OLED_SDA 4
|
||||
#define OLED_SCL 15
|
||||
#define OLED_RST 16
|
||||
#define OLED_DISPLAY_HAS_RST_PIN
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 25
|
||||
#define BATTERY_PIN 37
|
||||
|
||||
#define ADC_CTRL_PIN 21
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
11
variants/heltec-lora32-v2_915/platformio.ini
Normal file
11
variants/heltec-lora32-v2_915/platformio.ini
Normal file
@@ -0,0 +1,11 @@
|
||||
[env:heltec-lora32-v2_915]
|
||||
board = ttgo-lora32-v21
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-D RADIOLIB_EXCLUDE_LR11X0=1
|
||||
-D RADIOLIB_EXCLUDE_SX126X=1
|
||||
-D RADIOLIB_EXCLUDE_SX128X=1
|
||||
-D HELTEC_V2_915
|
||||
lib_deps =
|
||||
${common.lib_deps}
|
||||
${common.display_libs}
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
59
variants/heltec_vision_master_e290/board_pinout.h
Normal file
59
variants/heltec_vision_master_e290/board_pinout.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 39
|
||||
#define BOARD_I2C_SCL 38
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
#define HAS_EPAPER
|
||||
#define EPAPER_BUSY 6
|
||||
#define EPAPER_RST 5
|
||||
#define EPAPER_DC 4
|
||||
#define EPAPER_CS 3
|
||||
#define EPAPER_SCL 2
|
||||
#define EPAPER_SDA 1
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 45
|
||||
#define BATTERY_PIN 7
|
||||
|
||||
#define ADC_CTRL_PIN 46
|
||||
#define ADC_CTRL_ON_STATE HIGH
|
||||
#define VEXT_CTRL_PIN 18
|
||||
#define VEXT_CTRL_ON_STATE HIGH
|
||||
|
||||
#endif
|
||||
13
variants/heltec_vision_master_e290/platformio.ini
Normal file
13
variants/heltec_vision_master_e290/platformio.ini
Normal file
@@ -0,0 +1,13 @@
|
||||
[env:heltec_vision_master_e290]
|
||||
board = esp32-s3-devkitc-1
|
||||
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_VM_E290
|
||||
-D Vision_Master_E290
|
||||
lib_deps =
|
||||
${common.lib_deps}
|
||||
https://github.com/todd-herbert/heltec-eink-modules.git
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 41
|
||||
#define BOARD_I2C_SCL 42
|
||||
|
||||
@@ -53,7 +53,10 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 35
|
||||
#define BATTERY_PIN 1
|
||||
#define VEXT_CTRL 36
|
||||
#define ADC_CTRL 37
|
||||
|
||||
#define ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE HIGH
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_OLED_PINS
|
||||
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 41
|
||||
#define BOARD_I2C_SCL 42
|
||||
|
||||
@@ -53,7 +53,10 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 35
|
||||
#define BATTERY_PIN 1
|
||||
#define VEXT_CTRL 36
|
||||
#define ADC_CTRL 37
|
||||
|
||||
#define ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE HIGH
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
78
variants/heltec_wifi_lora_32_V4/board_pinout.h
Normal file
78
variants/heltec_wifi_lora_32_V4/board_pinout.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 SENSOR_I2C_BUS Wire1
|
||||
#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 ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE HIGH
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
// 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}
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -51,5 +51,5 @@
|
||||
Yellow LED (Wifi): PIN 23 / GPIO0
|
||||
Blue LED (BT/BLE): PIN 25 / GPIO16
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -33,7 +33,7 @@
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_14
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 37
|
||||
#define BOARD_I2C_SCL 36
|
||||
|
||||
@@ -50,7 +50,10 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 18
|
||||
#define BATTERY_PIN 20
|
||||
#define ADC_CTRL 19
|
||||
#define VEXT_CTRL 45
|
||||
|
||||
#define ADC_CTRL_PIN 19
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 45
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
59
variants/heltec_wireless_paper_v1_2/board_pinout.h
Normal file
59
variants/heltec_wireless_paper_v1_2/board_pinout.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 37
|
||||
#define BOARD_I2C_SCL 36
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
#define HAS_EPAPER
|
||||
#define EPAPER_BUSY 7
|
||||
#define EPAPER_RST 6
|
||||
#define EPAPER_DC 5
|
||||
#define EPAPER_CS 4
|
||||
#define EPAPER_SCL 3
|
||||
#define EPAPER_SDA 2
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 18
|
||||
#define BATTERY_PIN 20
|
||||
|
||||
#define ADC_CTRL_PIN 19
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 45
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
14
variants/heltec_wireless_paper_v1_2/platformio.ini
Normal file
14
variants/heltec_wireless_paper_v1_2/platformio.ini
Normal file
@@ -0,0 +1,14 @@
|
||||
[env:heltec_wireless_paper_v1_2]
|
||||
board = esp32-s3-devkitc-1
|
||||
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_WP_V1_2
|
||||
-D WIRELESS_PAPER
|
||||
-D V1_2
|
||||
lib_deps =
|
||||
${common.lib_deps}
|
||||
https://github.com/todd-herbert/heltec-eink-modules.git
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -50,8 +50,12 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 35
|
||||
#define BATTERY_PIN 1
|
||||
#define VEXT_CTRL 36
|
||||
#define ADC_CTRL 37
|
||||
|
||||
#define ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#define BOARD_I2C_SDA 41
|
||||
#define BOARD_I2C_SCL 42
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -33,14 +33,17 @@
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_14
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 41
|
||||
#define BOARD_I2C_SCL 42
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 35
|
||||
#define BATTERY_PIN 1
|
||||
#define VEXT_CTRL 36
|
||||
#define ADC_CTRL 37
|
||||
|
||||
#define ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -33,7 +33,7 @@
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_14
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE1_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire1
|
||||
#define BOARD_I2C_SDA 41
|
||||
#define BOARD_I2C_SCL 42
|
||||
|
||||
@@ -44,7 +44,10 @@
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 35
|
||||
#define BATTERY_PIN 1
|
||||
#define VEXT_CTRL 36
|
||||
#define ADC_CTRL 37
|
||||
|
||||
#define ADC_CTRL_PIN 37
|
||||
#define ADC_CTRL_ON_STATE LOW
|
||||
#define VEXT_CTRL_PIN 36
|
||||
#define VEXT_CTRL_ON_STATE LOW
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -33,19 +33,22 @@
|
||||
#define GPIO_WAKEUP_PIN GPIO_SEL_14
|
||||
|
||||
// I2C
|
||||
#define USE_WIRE_WITH_BOARD_I2C_PINS
|
||||
#define SENSOR_I2C_BUS Wire
|
||||
#define BOARD_I2C_SDA 7
|
||||
#define BOARD_I2C_SCL 6
|
||||
|
||||
|
||||
// Display
|
||||
#define HAS_DISPLAY
|
||||
#define HAS_TFT
|
||||
|
||||
// Aditional Config
|
||||
#define INTERNAL_LED_PIN 18
|
||||
#define BATTERY_PIN 1
|
||||
#define ADC_CTRL 2 // HELTEC Wireless Tracker ADC_CTRL = HIGH powers the voltage divider to read BatteryPin. Only on V05 = V1.1
|
||||
#define VEXT_CTRL 3 // To turn on GPS and TFT
|
||||
#define BATTERY_PIN 1
|
||||
|
||||
#define ADC_CTRL_PIN 2 // HELTEC Wireless Tracker ADC_CTRL = HIGH powers the voltage divider to read BatteryPin. Only on V05 = V1.1
|
||||
#define ADC_CTRL_ON_STATE HIGH
|
||||
#define VEXT_CTRL_PIN 3 // To turn on GPS and TFT
|
||||
#define VEXT_CTRL_ON_STATE HIGH
|
||||
|
||||
// GPS
|
||||
#define HAS_GPS
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
@@ -48,5 +48,5 @@
|
||||
#define INTERNAL_LED_PIN 25 // Green Led
|
||||
#define BATTERY_PIN 35
|
||||
#define HAS_ADC_CALIBRATION
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,17 @@
|
||||
/* 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
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user