Compare commits

...

260 Commits
V1.0.4 ... UEM4

Author SHA1 Message Date
richonguzman
3cc8fed15f preparing readme 2025-04-24 19:48:33 -04:00
richonguzman
725be9fed5 HWT works 2025-04-24 19:32:46 -04:00
richonguzman
16d9ef1c06 more testing to do 2025-04-24 18:08:25 -04:00
richonguzman
d2b7c063f7 hwt not ready 2025-04-24 18:02:29 -04:00
richonguzman
eaced15265 pruebas3 2025-04-24 18:01:00 -04:00
richonguzman
af4bc20ac2 t-beam ok 2025-04-24 16:32:58 -04:00
richonguzman
14473cb7c7 Sleep fix when saving Config 2025-04-24 16:17:29 -04:00
richonguzman
aba82ef3e0 prueba5 2025-04-24 15:56:13 -04:00
richonguzman
79405abe06 prueba5 2025-04-24 14:47:12 -04:00
richonguzman
c623c0502e prueba3 2025-04-24 14:43:47 -04:00
richonguzman
a6ae8523fa prueba2 2025-04-24 14:05:00 -04:00
richonguzman
d454ab4ba2 pruebas1 2025-04-24 13:26:34 -04:00
richonguzman
5146db796e cambio8 2025-04-24 11:30:03 -04:00
richonguzman
93e536e739 cambio7 2025-04-24 11:18:02 -04:00
richonguzman
0af4670dee cambio6 2025-04-24 11:09:39 -04:00
richonguzman
d70a35de1c cambio5 2025-04-24 10:46:04 -04:00
richonguzman
eb5b3aaa25 cambio4 2025-04-24 10:36:08 -04:00
richonguzman
ae3947b7ea cambio3 2025-04-24 09:50:58 -04:00
richonguzman
4f9eac9e5c cambio2 2025-04-24 09:44:57 -04:00
richonguzman
e689bb592c cambio1 2025-04-24 08:07:29 -04:00
richonguzman
786f5bdc0e update uppercase warning 2025-04-22 16:27:55 -04:00
richonguzman
ea2a83bc26 readme update 2025-03-23 22:23:29 -03:00
richonguzman
c406b67484 rename Web015-Manager.pnh 2025-03-20 17:52:32 -03:00
richonguzman
7cc397ea33 add Web15-Manager.png 2025-03-20 17:51:59 -03:00
richonguzman
503aba71d0 readme update 2025-03-20 16:02:19 -03:00
richonguzman
8b7e0fdcef minor correction to EM activation 2025-03-20 15:54:19 -03:00
richonguzman
ad996c8a49 encoded byte update 2025-03-18 19:10:15 -03:00
richonguzman
dedd7152d9 first update of timestamp 2025-03-18 18:50:08 -03:00
richonguzman
5f5d7d7868 ready for test 2025-03-18 14:02:09 -03:00
richonguzman
2e3cafd0f0 3 2025-03-10 03:02:48 -03:00
richonguzman
1c07c2fb2b 2 2025-03-09 10:48:18 -03:00
richonguzman
4c63dd8bb7 start1 2025-03-09 10:23:34 -03:00
richonguzman
b00fba9693 readme update 2025-03-03 13:53:29 -03:00
richonguzman
37162b9708 display font size correction 2025-03-03 12:22:22 -03:00
richonguzman
44d9732aa2 TbeamSupreme Added 2025-03-03 12:15:50 -03:00
richonguzman
312bdc9d9f refactor and blacklist2.0 2025-03-03 11:19:25 -03:00
richonguzman
ff0b96bfe4 readme update again 2025-02-28 16:56:54 -03:00
richonguzman
36a8ef0ffb readme update for epaper 2025-02-28 16:53:16 -03:00
richonguzman
5ce8059040 epaper updated 2025-02-28 16:48:26 -03:00
richonguzman
60aef00b24 function name correction 2025-02-25 14:15:30 -03:00
richonguzman
72c2c144ae last corrections 2025-02-25 14:01:14 -03:00
richonguzman
a1c552f197 readme update 2025-02-25 13:56:27 -03:00
richonguzman
8ede848199 ready for testing 2025-02-25 13:54:36 -03:00
richonguzman
a4a82b75c5 more testing 2025-02-24 18:49:17 -03:00
richonguzman
64ac924f1f first proposal 2025-02-24 17:57:24 -03:00
richonguzman
bde4a7f042 trim mod 2025-02-24 17:08:53 -03:00
richonguzman
d54b63df22 telemetry conf packet start after first beacon 2025-02-24 16:36:52 -03:00
richonguzman
c3d94d673a height correction with gps 2025-02-24 16:17:01 -03:00
richonguzman
45edf2ffa3 gps satelites indicator 2025-02-24 16:10:02 -03:00
richonguzman
d628de9c9c code cleaned to lighter versions 2025-02-12 15:28:48 -03:00
richonguzman
f879182f62 new mods 2025-02-12 14:15:36 -03:00
richonguzman
c9ed618a8b t-deck readme update 2025-01-22 09:52:22 -03:00
richonguzman
6c7b8f9918 readme update 2025-01-22 09:40:42 -03:00
richonguzman
c2b4b3b92f readme update 2025-01-22 01:35:28 -03:00
richonguzman
f7319ce591 avoid msg TX-RF of telemetry declaration 2025-01-22 00:12:11 -03:00
richonguzman
858162eb9c version and readme update 2025-01-22 00:00:46 -03:00
richonguzman
100b002309 tdeck ready 2025-01-21 23:57:56 -03:00
richonguzman
3acf73bf5f Tdeck working 2025-01-21 23:00:49 -03:00
richonguzman
53675e8084 upload blackList 2025-01-14 15:15:28 -03:00
richonguzman
4349019f7b version and readme UPDATE 2025-01-11 10:44:40 -03:00
richonguzman
411753c0aa build.yml updated 2025-01-10 12:15:32 -03:00
richonguzman
ad6aed7f0d starting with Heltec V3_2 2025-01-10 11:53:52 -03:00
richonguzman
f325c54fc3 Heltec Wireless Stick display fix 2025-01-08 12:59:39 -03:00
richonguzman
1a3966eadc readme update 2025-01-07 16:10:35 -03:00
richonguzman
ffd3eaeb49 fixes for beaconUpdate 2025-01-07 14:19:06 -03:00
richonguzman
df03a49123 version update 2025-01-06 10:14:51 -03:00
richonguzman
58d647bad1 added gps to troy 2025-01-06 09:33:47 -03:00
richonguzman
59988fbaf1 ready for testing 2025-01-05 12:32:46 -03:00
richonguzman
1ad13e3c09 gmt 15min fix 2025-01-04 12:30:22 -03:00
richonguzman
ffe1a2f830 gmt correction for 15 min 2025-01-02 12:20:18 -03:00
richonguzman
a0fdd78cb1 GMT to 15min step 2025-01-02 11:49:53 -03:00
richonguzman
95e437cb50 readme update 2025-01-01 21:58:24 -03:00
richonguzman
9c488991e2 ready for testing 2025-01-01 21:57:21 -03:00
richonguzman
ddcd33b94a blackList working 2025-01-01 21:56:13 -03:00
richonguzman
b688391a0e wildcard and two stations blacklisted OK 2025-01-01 21:42:37 -03:00
richonguzman
56d63d0389 base lista 2025-01-01 13:02:38 -03:00
richonguzman
ad5a5ccf18 digiEcoMode fix 2024-12-31 17:40:16 -03:00
richonguzman
92bc0a7667 readme update 2024-12-30 18:28:18 -03:00
richonguzman
ffcfc42b8a digirepeater Beacon fixed 2024-12-30 18:02:20 -03:00
richonguzman
f3e0830473 new byte for syslog 2024-12-11 18:03:13 -03:00
richonguzman
62107a5b4a passcode verified 2024-12-06 12:03:37 -03:00
richonguzman
9801545965 update1 2024-12-04 13:59:46 -03:00
richonguzman
dd89f56436 added xiao board 2024-12-04 09:12:22 -03:00
richonguzman
27593d8718 Xiao added 2024-12-04 08:46:07 -03:00
richonguzman
008575b422 test1 2024-12-04 08:09:54 -03:00
richonguzman
b8eedabe9a starting Xiao 2024-12-04 07:59:03 -03:00
richonguzman
7371b8e37a heltec v2 screen update 2024-11-20 14:43:48 -03:00
richonguzman
44605e82c2 define OLED_DISPLAY_HAS_RST_PIN 2024-11-20 11:26:29 -03:00
richonguzman
0360085131 minor code cleaning 2024-11-16 08:13:29 -03:00
richonguzman
57f720b0d1 small code cleaning on 25SecBuffer 2024-11-16 08:02:15 -03:00
richonguzman
3d01ea03c0 syslog server update 2024-11-07 09:34:27 -03:00
richonguzman
afb6a60bfe readme update 2024-11-06 12:49:37 -03:00
richonguzman
06ef37e4dc eliminando espacios en blanco 2024-11-06 12:47:42 -03:00
richonguzman
9159362796 update 2024-11-06 10:07:44 -03:00
richonguzman
47c136fdd5 correcciones 2024-11-05 23:51:10 -03:00
richonguzman
970d743b80 refactor inis 2024-11-05 23:21:05 -03:00
richonguzman
7c5e58f3b2 ready for testing 2024-11-05 19:14:22 -03:00
richonguzman
210c7acb70 testing3 2024-11-05 18:20:44 -03:00
richonguzman
8d102a73c1 testing2 2024-11-05 18:15:39 -03:00
richonguzman
5030d2d645 casi casi1 2024-11-05 16:59:21 -03:00
richonguzman
a95f55273f up1 2024-11-05 16:10:41 -03:00
richonguzman
4014db03c8 2 listas 2024-11-05 15:14:56 -03:00
richonguzman
d96d5f1963 testing 2024-11-05 14:41:41 -03:00
richonguzman
d1cb732ae1 33 folders 2024-11-05 14:12:56 -03:00
richonguzman
1504bf5a7f code cleaning 2024-10-29 18:57:23 -03:00
richonguzman
3c27e52df7 readme update for T3S3 2024-10-29 10:13:23 -03:00
richonguzman
3d5f3a4914 add Lilygo T3S3 2024-10-29 09:57:26 -03:00
richonguzman
db6292ce59 added but reboots 2024-10-28 09:33:27 -03:00
richonguzman
7995d23779 cleaned 2024-10-25 15:56:03 -03:00
richonguzman
7f150bc4a0 minor letter fix 2024-10-25 15:22:24 -03:00
richonguzman
ff5650f0c5 readme and build update 2024-10-25 12:50:15 -03:00
richonguzman
a91f0f3f3c WIRE update 2024-10-25 11:50:57 -03:00
richonguzman
c9577b6c21 more display testing 2024-10-25 11:08:00 -03:00
richonguzman
10cb7c6e45 added LightGateway 2024-10-25 10:42:15 -03:00
richonguzman
99052e594a typo fix 2024-10-23 12:09:24 -03:00
richonguzman
a05917c494 update 2024-10-22 22:14:29 -03:00
richonguzman
e2e935797f images update for V2.1 2024-10-21 12:26:40 -03:00
richonguzman
5ceff0064f small update to avoid sending gps = 0 2024-10-21 11:16:31 -03:00
richonguzman
8beb7c0465 readme update 2024-10-21 09:09:47 -03:00
richonguzman
112e38312d codingRate4 = 4 does not exists 2024-10-21 09:08:53 -03:00
richonguzman
5a1c6e7ed9 testing GPS 2024-10-21 08:28:35 -03:00
richonguzman
0defd5b289 added HWT with GPS 2024-10-14 17:48:14 -03:00
richonguzman
cdac54c34e cleaning code 2024-10-14 17:44:01 -03:00
richonguzman
71e98487f6 readme and index update 2024-10-14 17:23:42 -03:00
richonguzman
510b5bdc59 index reads better 2024-10-14 17:15:56 -03:00
richonguzman
00db358cc3 GPS for iGate 2024-10-14 17:04:28 -03:00
richonguzman
c0641986aa RxPacket freeze fix 2024-10-14 12:49:01 -03:00
richonguzman
55378bb9f3 readme Update for NTP update 2024-10-14 11:56:48 -03:00
richonguzman
79cf50a630 NTP time added 2024-10-14 11:44:22 -03:00
richonguzman
03ccd2b12e r up 2024-10-11 07:16:44 -03:00
richonguzman
d5ffd26c3c double validation for DigiEcoMode start stop 2024-10-10 18:45:12 -03:00
richonguzman
2f0f991785 readme2 2024-10-09 11:46:45 -03:00
richonguzman
975b140c73 readme1 2024-10-09 11:45:01 -03:00
richonguzman
f2abe34af1 readme Update Digi Eco Mode 2024-10-08 12:25:09 -03:00
richonguzman
a786d83b9e Queries for DigiEcoMode 2024-10-08 12:19:22 -03:00
richonguzman
bf0a0d6e4c EcoMode Digi 2024-10-08 11:04:36 -03:00
richonguzman
d08e5b1b27 ready for testing LowPowerDigi 2024-10-08 01:22:10 -03:00
richonguzman
f387e03b53 testing LowPowerDigi 2024-10-08 01:03:58 -03:00
richonguzman
16215f9e56 minor update for Internal Battery Sleep 2024-10-07 11:10:19 -03:00
richonguzman
ce01d0aa4d minor white spaces kill 2024-10-07 09:39:31 -03:00
richonguzman
b0a05f89f6 readme update 2024-10-06 23:35:51 -03:00
richonguzman
58d8736969 test for Killed Wifi Active 2024-10-06 23:23:22 -03:00
richonguzman
df9060d906 testing not active 2024-10-06 23:02:10 -03:00
richonguzman
2bd6844d89 WiFiAP Active switch added 2024-10-06 22:59:58 -03:00
richonguzman
0a79b6459b added initial corrections to WiFiAP 2024-10-06 22:30:44 -03:00
richonguzman
d5eb32a38b cross digi rules added 2024-10-06 11:37:25 -03:00
richonguzman
d6c5741fde cross digi added 2024-10-06 11:36:37 -03:00
richonguzman
1063a82294 se viene thirdParty 2024-10-05 20:25:29 -03:00
richonguzman
6913b6b89f ahora a probar thirdParty 2024-10-05 20:23:58 -03:00
richonguzman
42c990f5cf !thirdParty con o sin path 2024-10-05 20:21:36 -03:00
richonguzman
a17900e4d0 bme into wxsensor 2024-10-05 08:48:08 -03:00
richonguzman
3fd819bd4e not encoded telemetry as default 2024-09-25 11:23:38 -03:00
richonguzman
640166a50b update for wiki 2024-09-23 17:41:05 -03:00
richonguzman
a9bcae62e2 readme update 2024-09-23 15:15:22 -03:00
richonguzman
3e0368383a better writting 2024-09-23 15:11:35 -03:00
richonguzman
8b790ef656 updated libraries for SDK3 2024-09-23 14:31:45 -03:00
richonguzman
c110b41b99 build update for new boards 2024-09-23 12:42:03 -03:00
richonguzman
be7fe23cd5 Added LLCC68 1W board 2024-09-23 12:37:35 -03:00
richonguzman
202d03c61f shortening reduced Wx report 2024-09-23 12:15:58 -03:00
richonguzman
ddb45544db readme UPdate 2024-09-22 22:35:51 -03:00
richonguzman
c9ea51c6da update Version 2024-09-22 22:34:00 -03:00
richonguzman
72fd2b45ec added mods to include Telemetry 2024-09-22 22:31:33 -03:00
richonguzman
0e46c64880 primera mejora Telemetria 2024-09-22 13:34:13 -03:00
richonguzman
dd12330e85 killing some delays 2024-09-17 14:25:00 -03:00
richonguzman
2edb183cad minor update on Heltec WS 2024-09-11 16:14:40 -03:00
richonguzman
775677d5e8 trying heltec wireless stick oled fix 2024-09-11 15:49:58 -03:00
richonguzman
a60a6d6e4b update WIRE 2024-09-10 14:26:10 -03:00
richonguzman
14abe14703 updated structs of last Stations and 25seg buffer 2024-09-10 14:06:10 -03:00
richonguzman
345fb1e937 up 2024-09-02 09:40:17 -04:00
richonguzman
916eb038e5 updated WiFi.setHostName() 2024-09-02 09:12:18 -04:00
richonguzman
40fc177828 small fix on wire begin 2024-08-30 15:46:50 -04:00
richonguzman
5dc6e99972 low external voltage RF Tx fix 2024-08-28 17:11:50 -04:00
richonguzman
db5710ec6a test 2024-08-28 12:21:54 -04:00
richonguzman
65acb54dbe wrong external sleep voltage definition fix 2024-08-28 11:45:16 -04:00
richonguzman
6088c61e73 versionUpdate + utils beacon message update 2024-08-26 10:33:49 -04:00
Ricardo Guzman (Richonguzman)
a8c972c5e1 Merge pull request #157 from S57PNX/main
Correct logic of serial notifications for APRS-IS and RF beacons
2024-08-26 10:32:01 -04:00
S57PNX
bd3a9f91d6 Merge branch 'richonguzman:main' into main 2024-08-26 10:25:17 +02:00
richonguzman
643a18f40c Wemos S2 Mini DIY LoRa added 2024-08-23 18:05:27 -04:00
richonguzman
46e5bdd21e added led 2024-08-23 18:00:25 -04:00
richonguzman
ea426f4126 board update 2024-08-22 16:27:41 -04:00
richonguzman
5cbdd318a2 test for WEMOS S2 Mini DIY LORA 2024-08-22 15:00:56 -04:00
richonguzman
735988ee1c adding WEMOS S2 MINI 2024-08-22 14:24:30 -04:00
richonguzman
d5b666f458 HELTEC WS update 2024-08-22 13:25:46 -04:00
richonguzman
702f4abcbb update for gps beacon with timestamp 2024-08-21 19:11:05 -04:00
richonguzman
d0070e4381 updated config 2024-08-20 19:01:04 -04:00
richonguzman
f4744eab6a Heltec Wireless Paper base 2024-08-19 11:37:55 -04:00
richonguzman
bd672857f4 testing for external battery block 2024-08-19 10:41:46 -04:00
richonguzman
9cc26ccdae wireless paper battery reading fix 2024-08-18 21:06:57 -04:00
richonguzman
8863838210 updated battery readings 2024-08-17 13:16:44 -04:00
richonguzman
f11b6de57a fix for normal display 2024-08-16 16:00:58 -04:00
richonguzman
55d6bc325f version update 2024-08-16 15:52:55 -04:00
richonguzman
ee687e6959 first test 2024-08-16 15:52:20 -04:00
S57PNX
d1732a6bba Correct logic of serial notifications for APRS-IS
and RF beacons
2024-08-15 20:54:26 +02:00
richonguzman
4fb4712a33 backupDigimode avoided in only rx mode 2024-08-14 13:37:52 -04:00
richonguzman
39276b0d32 update to display h and cpp 2024-08-14 12:32:34 -04:00
richonguzman
22203a7c24 just code cleaning 2024-08-14 12:07:17 -04:00
richonguzman
d8d832fde9 configuration test without fails 2024-08-14 11:50:39 -04:00
richonguzman
61db6c3132 backUpDigiMode and BME for HWSL v3 fix 2024-08-13 17:56:27 -04:00
richonguzman
9521a357b1 readmeUpdate 2024-08-13 14:49:30 -04:00
richonguzman
ee95931f00 web user and password 2024-08-13 14:48:08 -04:00
richonguzman
60aa2b05ac more boards update 2024-08-13 12:46:20 -04:00
richonguzman
bc5183a192 Ht-ct62 updates 2024-08-13 12:36:37 -04:00
richonguzman
1019306c7c wide2-n fix 2024-08-12 13:49:58 -04:00
richonguzman
fbe00903ad version Date on footer added 2024-08-12 11:01:35 -04:00
richonguzman
291a6bc80e added mesh - diy board v1-2 2024-08-12 10:35:45 -04:00
richonguzman
3b550c7f81 mode3 fix WIDE2-2 2024-08-06 10:57:00 -04:00
richonguzman
4659f8b2ff mode3start 2024-08-06 10:11:50 -04:00
richonguzman
62d157d7f0 state add at boot 2024-08-06 09:12:01 -04:00
richonguzman
b0e116ee1d Readme Update Digis 2024-08-05 17:42:59 -04:00
richonguzman
00b12c2bf5 version update 2024-08-05 15:43:42 -04:00
richonguzman
85b21565db index fix 2024-08-05 15:43:02 -04:00
richonguzman
b9e2c0e8f0 digimode 3 improvement 2024-08-05 15:42:33 -04:00
richonguzman
b763b4af78 RNAAAA add + WIDE2 description in index 2024-08-05 15:20:58 -04:00
richonguzman
5553e7ae5c added mode 3 for digirepeater 2024-08-05 14:37:16 -04:00
richonguzman
1afd039c3f digi mode 3 added 2024-08-03 21:55:32 -04:00
richonguzman
1888084f31 WSL v3 wire1 add 2024-08-02 16:15:10 -04:00
richonguzman
dc92b822c8 fixed missing wire begin 2024-08-02 15:28:31 -04:00
richonguzman
3c305259e0 update to recover from wifi AP 2024-08-02 13:08:54 -04:00
richonguzman
497d648c17 ready for testing 2024-07-18 14:41:09 -04:00
richonguzman
d267f6699c HWSL_V3_Display add 2024-07-17 16:20:20 -04:00
richonguzman
16ce6bc6d2 a7670 voltage calibration fix 2024-07-17 10:47:42 -04:00
richonguzman
008b6250ea Non Ham mods only for Rx 2024-07-10 15:13:57 -04:00
richonguzman
ddb83d1368 voltageCalibrationCorrection 2024-07-10 09:49:13 -04:00
richonguzman
26e2dec2b2 font size update 2024-07-09 10:41:26 -04:00
richonguzman
174507377b fix for other boards 2024-07-09 08:39:59 -04:00
richonguzman
864ed44a5d favicon and battery adc calibration 2024-07-08 23:29:04 -04:00
richonguzman
5d69cfbe1c 1 2024-07-08 23:06:03 -04:00
richonguzman
e57d356fd1 new ADC calibration test 2024-07-08 23:02:45 -04:00
richonguzman
8381f0916c variable name change 2024-07-05 13:12:21 -04:00
richonguzman
beca09293a queryUppercase fix 2024-07-05 11:58:18 -04:00
richonguzman
dcca18eeac readme Update 2024-07-01 18:30:11 -04:00
richonguzman
2494acea55 espacio en blanco 2024-06-30 10:36:15 -04:00
richonguzman
0c50ce8de4 tyeofpacket update 2024-06-30 09:24:21 -04:00
richonguzman
2f07d35861 readmeupdate7 2024-06-28 16:20:07 -04:00
richonguzman
91240c5be6 readmeupdate6 2024-06-28 16:19:18 -04:00
richonguzman
b4308a95d5 readmeupdate5 2024-06-28 16:18:41 -04:00
richonguzman
6c301795d6 readmeupdate4 2024-06-28 16:18:13 -04:00
richonguzman
5f0c6f4986 readmeupdate3 2024-06-28 16:15:56 -04:00
richonguzman
7c989e6e9e readmeupdate2 2024-06-28 16:15:22 -04:00
richonguzman
2bcda6d3a4 readme update 2024-06-28 16:14:42 -04:00
richonguzman
848492dc36 updated QueryAnswer for 3rdPartyPacket 2024-06-28 16:05:04 -04:00
richonguzman
413bef67fb readme update 2024-06-27 16:25:58 -04:00
richonguzman
3fa4c9371a new battery web config 2024-06-27 16:02:20 -04:00
richonguzman
e846c38f97 externalBatdivider 2024-06-27 15:39:53 -04:00
richonguzman
b8446e3f1d bat and sh gone 2024-06-27 13:19:51 -04:00
richonguzman
c3984bc8da casi listo para prueba 2024-06-26 23:42:24 -04:00
richonguzman
601b72da9f funciona 2024-06-26 18:13:02 -04:00
richonguzman
5d9493314d casi 2024-06-26 17:56:11 -04:00
richonguzman
86cf12d6c1 carga datos base 2024-06-26 17:10:07 -04:00
richonguzman
e5e2c6a980 readmeUpdate 2024-06-26 13:26:17 -04:00
richonguzman
3b9d49c5f9 personalNote implementation 2024-06-26 13:24:36 -04:00
richonguzman
ab9443140b personalNote1 2024-06-26 13:05:45 -04:00
richonguzman
ad1129c588 callsign validation process fix 2024-06-25 16:36:49 -04:00
richonguzman
8bb0b0446c more 3rd party filtering 2024-06-24 13:25:30 -04:00
richonguzman
6b1d319901 fix firstColon on last position 2024-06-24 11:36:40 -04:00
richonguzman
1ceaf159ba colonIndex fix3 2024-06-24 11:18:42 -04:00
richonguzman
f1de8d2df0 colonIndex upload fix 2024-06-24 11:16:52 -04:00
richonguzman
b9b4f46c66 typeOfPacket fix3 2024-06-24 11:02:38 -04:00
richonguzman
22b2c679d2 typeofPacket initial fix 2024-06-24 10:54:21 -04:00
richonguzman
7baa98bf7e first 3rdparty correction 2024-06-24 10:32:58 -04:00
156 changed files with 4662 additions and 2229 deletions

View File

@@ -15,14 +15,20 @@ jobs:
chip: esp32
- name: ttgo-lora32-v21_915
chip: esp32
- name: ttgo_lora32_t3s3_v1_2
chip: esp32s3
- name: heltec-lora32-v2
chip: esp32
- name: heltec_wifi_lora_32_V3
chip: esp32s3
- name: heltec_wifi_lora_32_V3_2
chip: esp32s3
- name: heltec_wireless_stick
chip: esp32s3
- name: heltec_wireless_stick_lite_v3
chip: esp32s3
- name: heltec_wireless_stick_lite_v3_display
chip: esp32s3
- name: ESP32_DIY_LoRa
chip: esp32
- name: ESP32_DIY_LoRa_915
@@ -31,6 +37,10 @@ jobs:
chip: esp32
- name: ESP32_DIY_1W_LoRa_915
chip: esp32
- name: ESP32_DIY_1W_LoRa_LLCC68
chip: esp32
- name: ESP32_DIY_1W_LoRa_Mesh_V1_2
chip: esp32
- name: ttgo-t-beam-v1_2
chip: esp32
- name: ttgo-t-beam-v1_2_915
@@ -43,6 +53,12 @@ jobs:
chip: esp32
- name: ttgo-t-beam-v1_2_SX1262
chip: esp32
- name: ttgo_t_deck_plus
chip: esp32s3
- name: ttgo_t_deck_GPS
chip: esp32s3
- name: ttgo_t_beam_s3_SUPREME_v3
chip: esp32s3
- name: ESP32_DIY_LoRa_A7670
chip: esp32
- name: ESP32_DIY_LoRa_A7670_915
@@ -51,16 +67,28 @@ jobs:
chip: esp32s3
- name: heltec_ht-ct62
chip: esp32c3
- name: heltec_wireless_paper
chip: esp32s3
- name: OE5HWN_MeshCom
chip: esp32
- name: WEMOS-LOLIN32-OLED-DIY
chip: esp32
- name: WEMOS-D1-R32-RA02
chip: esp32
- name: WEMOS_S2_MINI_DIY_LoRa
chip: esp32s2
- name: esp32c3_DIY_1W_LoRa
chip: esp32c3
- name: esp32c3_DIY_1W_LoRa_915
chip: esp32c3
- name: ESP32_C3_OctopusLab_LoRa
chip: esp32c3
- name: QRPLabs_LightGateway_1_0
chip: esp32s3
- name: XIAO_ESP32S3_WIO_SX1262
chip: esp32s3
- name: TROY_LoRa_APRS
chip: esp32
steps:
- uses: actions/checkout@v3
@@ -102,6 +130,17 @@ jobs:
0xe000 installer/firmware/boot_app0.bin \
0x10000 installer/firmware/firmware.bin \
0x3D0000 installer/firmware/spiffs.bin
elif [ "${{ matrix.target.chip }}" == "esp32s2" ]; then
python installer/bin/esptool/esptool.py --chip esp32s2 merge_bin \
-o installer/web_factory.bin \
--flash_mode dio \
--flash_freq 40m \
--flash_size 4MB \
0x1000 installer/firmware/bootloader.bin \
0x8000 installer/firmware/partitions.bin \
0xe000 installer/firmware/boot_app0.bin \
0x10000 installer/firmware/firmware.bin \
0x3D0000 installer/firmware/spiffs.bin
elif [ "${{ matrix.target.chip }}" == "esp32s3" ]; then
python installer/bin/esptool/esptool.py --chip esp32s3 merge_bin \
-o installer/web_factory.bin \

View File

@@ -1,18 +1,19 @@
# Richonguzman / CA2RXU LoRa APRS iGate/Digirepeater
# CA2RXU LoRa APRS iGate/Digipeater
This firmware is for using ESP32 based boards with LoRa Modules and GPS to live in the APRS world.
![Screenshot](https://github.com/richonguzman/LoRa_APRS_iGate/blob/main/images/iGateOledScreen.jpeg)
__(This iGate Firmware works with all LoRa Tracker Firmwares (specially this <a href="https://github.com/richonguzman/LoRa_APRS_Tracker" target="_blank">LoRa APRS Tracker Firmware</a>))__
<br />
___________________________________________________
____________________________________________________
## You can support this project to continue to grow:
[<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/github-sponsors.png">](https://github.com/sponsors/richonguzman) [<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/paypalme.png">](http://paypal.me/richonguzman)
____________________________________________________
<br />
# WEB FLASHER/INSTALLER is <a href="https://richonguzman.github.io/lora-igate-web-flasher/installer.html" target="_blank">here</a>
@@ -23,9 +24,7 @@ ____________________________________________________
### FAQ, BME280, TNC and more --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/00.-FAQ-(frequently-asked-questions)" target="_blank">here</a>.
### Installation Guide --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/01.-Installation-Guide" target="_blank">here</a>.
____________________________________________________
<br />
# SUPPORTED BOARDS
@@ -33,11 +32,15 @@ ____________________________________________________
(NOTE: all boards with 433-868-915 MHz versions)
- TTGO Lilygo LoRa32 v2.1 / v1.6 (they work the same).
- TTGO Lilygo LoRa32 T3S3 V1.2 and LoRa32 V2.1 (V1.6 is the same).
- TTGO T-Beam v1.0 , v1.1, v1.2 (also variations with SX1262 and SX1268 LoRa Modules).
- TTGO T-Beam V1.0 , V1.1, V1.2 (also variations with SX1262 and SX1268 LoRa Modules).
- HELTEC V2, V3 , Wireless Stick, Wireless Stick Lite, HT-CT62, Wireless Tracker.
- T-Deck Plus (and also regular T-Deck with/without GPS).
- HELTEC V2, V3 , Wireless Stick, Wireless Stick Lite, HT-CT62, Wireless Tracker, Wireless Paper.
- QRP Labs LightGateway 1.0.
- ESP32 Wroom + SX1278 LoRa Module or Ebyte 400M30S (or 900M30S) 1W LoRa Module for a DIY Versions.
@@ -47,17 +50,45 @@ ____________________________________________________
- Wemos Lolin32 Oled + SX1278 DIY Version.
____________________________________________________
<br />
## Timeline (Versions):
- 2024.06.21 Tx packets coming from APRS-IS are (now) formatted into 3rd Party (as they should have been since the beginning).
- 2025-04-20000000
- 2025.03.20 Manager List added to enable/disable DigiEcoMode and Tx Control. Thanks LB5JJ.
- 2025.03.03 T-Beam Supreme board added and more BlackList rules added.
- 2025.02.28 Heltec Wireless Paper with Epaper working. Thanks SzymonPriv for pointing to the right library.
- 2025.02.25 Objects Rules update, GPS Boards: Satellites on Screen, Wx Height Correction from GPS Data.
- 2025.01.22 Added LILYGO T-DECK PLUS (and DIY+GPS version) board support.
- 2025.01.11 Added HELTEC V3.2 board support.
- 2025.01.07 TROY_LoRa_APRS board added. GMT in quarter hour fix and Beacon fix for TNC.
- 2025.01.02 Callsign Black List added.
- 2024.12.30 Fixed missing validation for correct Digipeater mode when not connected to APRS-IS.
- 2024.12.06 APRS-IS connnection and passcode validation added.
- 2024.11.06 (Silent Update) Working now with Board "VARIANTS".
- 2024.10.29 Added LILYGO Lora32 T3S3 support.
- 2024.10.25 Added QRP Labs LightGateway 1.0 support.
- 2024.10.21 Boards with GPS can now send Real-GPS Beacon (also posible: GPS ambiguity of ~ 1 km).
- 2024.10.14 Received Packets in WebUI show real Local Time (NTP with GMT offset).
- 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.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.
- 2024.08.05 WIDE2-n added to WIDE1-n in Digipeater Modes.
- 2024.06.27 External Voltage Divider Resistor configuration on WebUI. Thanks Tilen S54B.
- 2024.06.26 Personal Note information on WebUI for the Station. Thanks Tilen S54B.
- 2024.06.24 Callsign Validation fix. Thanks Helge SA7SKY.
- 2024.06.21 Tx packets coming from APRS-IS are (now) formatted into 3rd Party (as they should have been since the beginning). Thanks Lynn KJ4ERJ and Geoffrey F4FXL.
- 2024.06.18 All boards with 433 / 868 / 915 MHz versions.
- 2024.06.10 ESP32C3 + 1W LoRa Module (E22 400M30S) support added.
- 2024.06.09 Si7021 module added (with autodetected I2C Address)
- 2024.06.08 Callsign Validation for all Station that iGate/Digi hears.
- 2024.05.27 Battery Monitor for internal and External Voltages (to make board sleep and avoid low discharge of batterys) T-Beam boards now with Battery readings as well.
- 2024.05.23 Forced Reboot Mode added.
- 2024.05.22 Experimental backup-Digirepeater-Mode when "only" iGate mode loses WiFi connection added.
- 2024.05.22 Experimental backup-Digipeater-Mode when "only" iGate mode loses WiFi connection added.
- 2024.05.20 WebConfig update to control whether Messages and Objects should be Tx to RF.
- 2024.05.17 HELTEC Wireless Stick Lite v3 support added.
- 2024.05.14 BME modules will be autodetected (I2C Address and if it is BME280/BMP280/BME680).
@@ -69,12 +100,12 @@ ____________________________________________________
- 2024.04.21 WEB INSTALLER (thanks Damian SQ2CPA).
- 2024.04.20 New Output Buffer process: no more packets lost.
- 2024.04.13 Received Packets added on WebUI.
- 2024.04.09 iGate/Digirepeater own GPS beacon is encoded (Base91) now.
- 2024.04.09 iGate/Digipeater own GPS beacon is encoded (Base91) now.
- 2024.03.18 OE5HWN MeshCom board support added.
- 2024.02.25 New Web Configuration UI with WiFi AP (thanks Damian SQ2CPA).
- 2023.01.28 Updated to ElegantOTA v.3 (AsyncElegantOTA was deprecated).
- 2024.01.19 TextSerialOutputForApp added to get text from Serial-Output over USB into PC for PinPoint App (https://www.pinpointaprs.com) and APRSIS32 App (http://aprsisce.wikidot.com)
- 2024.01.12 Added iGate Mode to also repeat packets (like a iGate+DigiRepeater) in stationMode 2 and 5.
- 2024.01.12 Added iGate Mode to also repeat packets (like a iGate+Digipeater) in stationMode 2 and 5.
- 2024.01.11 Added iGate Mode to enable APRS-IS and LoRa beacon report at the same time.
- 2024.01.05 Lilygo TTGO T-Beam V1, V1.2, V1 + SX1268, V1.2 + SX1262 support added.
- 2024.01.02 EByte 400M30S 1 Watt LoRa module for DIY ESP32 iGate support added.
@@ -83,18 +114,18 @@ ____________________________________________________
- 2023.12.07 MIC-E process and Syslog added.
- 2023.12.06 HELTEC V2 board support added.
- 2023.11.26 Small correction to enable Syslog in stationMode5.
- 2023.10.09 Added "WIDE1-1" to Tx packets from iGate to be *repeated* by Digirepeaters.
- 2023.10.09 Added "WIDE1-1" to Tx packets from iGate to be *repeated* by Digipeaters.
- 2023.10.09 BMP280 module support added.
- 2023.08.20 Added External Voltage Measurement (Max 15V!)
- 2023.08.05 Ground Height Correction for Pressure readings added.
- 2023.07.31 StationMode5 added: iGate when WiFi and APRS available, DigiRepeater when not.
- 2023.07.31 StationMode5 added: iGate when WiFi and APRS available, Digipeater when not.
- 2023.07.16 Small OTA, BME module update.
- 2023.07.05 Adding monitor info of Battery connected.
- 2023.06.18 Info on Oled Screen mayor update, added RSSI and Distance to Listened Station.
- 2023.06.17 BME280 Module (Temperature, Humidity, Pressure) support added.
- 2023.06.12 Syslog added.
- 2023.06.10 OTA update support for Firmware and Filesystem.
- 2023.06.08 Adding Digirepeater Functions.
- 2023.06.08 Adding Digipeater Functions.
- 2023.06.06 Full repack of Code and adding _enableTx_ only for Ham Ops.
- 2023.05.23 Processing Query's from RF/LoRa or APRS-IS (Send "Help" Message to test).
- 2023.05.19 Saving Last-Heard Stations for validating Tx Responses.
@@ -105,4 +136,4 @@ ____________________________________________________
__________________________________________
# Hope You Enjoy this, 73 !! CA2RXU , Valparaiso, Chile
# Hope You Enjoy this, 73! CA2RXU, Valparaiso, Chile

44
common_settings.ini Normal file
View File

@@ -0,0 +1,44 @@
[common]
build_flags =
-Werror -Wall
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
-DRADIOLIB_EXCLUDE_CC1101=1
-DRADIOLIB_EXCLUDE_NRF24=1
-DRADIOLIB_EXCLUDE_RF69=1
-DRADIOLIB_EXCLUDE_SX1231=1
-DRADIOLIB_EXCLUDE_SX1233=1
-DRADIOLIB_EXCLUDE_SI443X=1
-DRADIOLIB_EXCLUDE_RFM2X=1
-DRADIOLIB_EXCLUDE_AFSK=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_HELLSCHREIBER=1
-DRADIOLIB_EXCLUDE_MORSE=1
-DRADIOLIB_EXCLUDE_RTTY=1
-DRADIOLIB_EXCLUDE_SSTV=1
-DRADIOLIB_EXCLUDE_AX25=1
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_PAGER=1
-DRADIOLIB_EXCLUDE_FSK4=1
-DRADIOLIB_EXCLUDE_APRS=1
-DRADIOLIB_EXCLUDE_LORAWAN=1
-I variants/${PIOENV}
lib_deps =
adafruit/Adafruit Unified Sensor @ 1.1.14
adafruit/Adafruit BME280 Library @ 2.2.4
adafruit/Adafruit BMP280 Library @ 2.6.8
adafruit/Adafruit BME680 Library @ 2.0.4
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
mathieucarbou/AsyncTCP @ 3.2.5
mathieucarbou/ESPAsyncWebServer @ 3.2.3
mikalhart/TinyGPSPlus @ 1.0.3
display_libs =
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
usb_flags=
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1

View File

@@ -3,7 +3,7 @@
"wifi": {
"autoAP": {
"password": "1234567890",
"powerOff": 10
"timeout": 10
},
"AP": []
},
@@ -28,7 +28,8 @@
"objectsToRF": false
},
"digi": {
"mode": 0
"mode": 0,
"ecoMode": 0
},
"lora": {
"txFreq": 433775000,
@@ -48,21 +49,24 @@
"battery": {
"sendInternalVoltage": false,
"monitorInternalVoltage": false,
"internalSleepVoltage": 3.0,
"internalSleepVoltage": 2.9,
"sendExternalVoltage": false,
"externalVoltagePin": 34,
"monitorExternalVoltage": false,
"externalSleepVoltage": 10.9
"externalSleepVoltage": 10.9,
"voltageDividerR1": 100.0,
"voltageDividerR2": 27.0,
"sendVoltageAsTelemetry": false
},
"bme": {
"wxsensor": {
"active": false,
"heightCorrection": 0,
"temperatureCorrection": 0.0
},
"syslog": {
"active": false,
"server": "192.168.0.100",
"port": 514
"server": "lora.link9.net",
"port": 1514
},
"tnc": {
"enableServer": false,
@@ -73,12 +77,23 @@
"username": "",
"password": ""
},
"webadmin": {
"username": "admin",
"password": ""
},
"ntp": {
"gmtCorrection": 0.0
},
"remoteManagement": {
"managers": "",
"rfOnly": true
},
"other": {
"rememberStationTime": 30,
"lowPowerMode": false,
"lowVoltageCutOff": 0,
"backupDigiMode": false,
"rebootMode": false,
"rebootModeTime": 6
}
},
"personalNote": "",
"blacklist": ""
}

BIN
data_embed/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

View File

@@ -6,6 +6,7 @@
<title>LoRa iGate & Digi software &minus; Ricardo Guzman CA2RXU</title>
<link rel="stylesheet" href="/bootstrap.css" />
<link rel="stylesheet" href="/style.css" />
<link rel="icon" href="/favicon.png" type="image/x-icon">
</head>
<body class="bg-body-tertiary">
<input type="file" accept="text/json,.json" style="display: none" />
@@ -15,7 +16,7 @@
>
<div class="container">
<a class="navbar-brand" href=""
>CA2RXU's LoRa</a
>CA2RXU's LoRa iGate</a
>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@@ -61,11 +62,11 @@
<div class="container d-none" id="received-packets">
<div class="row my-5 d-flex align-items-top">
<div class="col-12">
<h3>Last 20 received packets list</h3>
<h3>Last 10 received packets list</h3>
<table class="table mt-4">
<thead>
<tr>
<th scope="col">Time*</th>
<th scope="col">Time</th>
<th scope="col">Frame</th>
<th scope="col">RSSI</th>
<th scope="col">SNR</th>
@@ -76,7 +77,7 @@
</tbody>
</table>
<span>List refresh automatically every 15 seconds.</span><br>
<small>* - For now time is measured from board boot up.</small>
<small>(Local Time is NTP-Time adjusted with your GMT Offset)</small>
</div>
</div>
<hr />
@@ -107,16 +108,20 @@
Station
</h5>
<small
>Add your ham callsign and SSID. Optionally,
you can leave a comment describing your
station.</small
>
>Add your Ham callsign and SSID.
<br>
<br>
You can leave a comment describing your station.
<br>
<br>
In the bottom there is a field for personal note that can only be seen in WEB GUI.
</small>
</div>
<div class="col-lg-9 col-sm-12">
<div class="row">
<div class="col-12">
<label for="callsign" class="form-label"
>Callsign and SSID</label
>Callsign - SSID</label
>
<input
type="text"
@@ -147,7 +152,7 @@
<label
for="beacon.path"
class="form-label"
>Beacon path</label
>Beacon Path</label
>
<input
type="text"
@@ -237,6 +242,20 @@
class="form-control"
/>
</div>
<div class="col-12 mt-3">
<label
for="personalNote"
class="form-label"
>Personal Note</label
>
<input
type="text"
name="personalNote"
id="personalNote"
class="form-control"
placeholder="A Couple of words."
/>
</div>
</div>
</div>
</div>
@@ -473,9 +492,8 @@
<label
for="beacon.sendViaAPRSIS"
class="form-label"
>Send our beacon to
APRS-IS</label
>
>Send beacon via APRS-IS
</label>
</div>
</div>
<div class="col-6">
@@ -489,21 +507,21 @@
<label
for="beacon.sendViaRF"
class="form-label"
>Send beacon via RF</label
>
>Send beacon via RF
</label>
</div>
</div>
<div class="col-6 d-grid gap-2">
<button class="btn btn-primary" id="send-beacon">Send beacon now</button>
</div>
</div>
<div class="row mt-3">
<div class="row mt-4">
<div class="col-12">
<label
for="beacon.interval"
class="form-label"
>Interval</label
>
>Beacon Interval
</label>
<div class="input-group">
<input
type="number"
@@ -513,14 +531,85 @@
class="form-control"
required=""
step="1"
min="1"
min="15"
/>
<span class="input-group-text"
>minutes</span
>
>minutes
</span>
</div>
</div>
</div>
<div class="col-12 mt-3">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.gpsActive"
id="beacon.gpsActive"
class="form-check-input"
/>
<label
for="beacon.gpsActive"
class="form-label"
>Send Real-GPS Beacon <small>(Only for Boards with GPS Modules)</small>
</label>
</div>
</div>
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="beacon.gpsAmbiguity"
id="beacon.gpsAmbiguity"
class="form-check-input"
/>
<label
for="beacon.gpsAmbiguity"
class="form-label"
>Send Real-GPS Beacon with Ambiguity <small>(~ 1 Km of Random Error)</small>
</label>
</div>
</div>
</div>
</div>
<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-broadcast-pin"
viewBox="0 0 16 16"
>
<path
d="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707m2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708m5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708m2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8"
/>
</svg>
Black List
</h5>
<small>Add Callsigns with space between them to Blacklist them (* wild card allowed)</small>
</div>
<div class="col-9 mt-2">
<div class="row">
<div class="col-12">
<label
for="blacklist"
class="form-label"
>Blacklist</label
>
<input
type="text"
name="blacklist"
id="blacklist"
class="form-control"
placeholder="Station Callsign"
oninput="this.value = this.value.toUpperCase();"
/>
</div>
</div>
</div>
</div>
<hr />
@@ -557,10 +646,37 @@
name="digi.mode"
id="digi.mode"
>
<option value="0">off</option>
<option value="0">
OFF
</option>
<option value="2">
WIDE1 (fill-in) Digi
</option>
<option value="3">
WIDE2 (+WIDE1) Digi
</option>
</select>
</div>
<div class="col-12 mt-3">
<label
for="digi.ecoMode"
class="form-label"
>Eco Mode</label
>
<select
class="form-select form-select"
name="digi.ecoMode"
id="digi.ecoMode"
>
<option value="0">
OFF (Normal Mode)
</option>
<option value="1">
Ultra Eco Mode (Sleep till Packet Rx (WiFiAP/WebUI & Display disabled))
</option>
<option value="2">
OFF (Normal Mode without WiFiAP)
</option>
</select>
</div>
</div>
@@ -625,8 +741,8 @@
<label
for="lora.txFreq"
class="form-label"
>Tx Frequency</label
>
>Tx Frequency
</label>
<div class="input-group">
<input
type="text"
@@ -644,17 +760,17 @@
class="form-control"
required=""
/>
<span class="input-group-text"
>Hz</span
>
<span class="input-group-text">
Hz
</span>
</div>
</div>
<div class="col-6">
<label
for="lora.rxFreq"
class="form-label"
>Rx Frequency</label
>
class="form-label">
Rx Frequency
</label>
<div class="input-group">
<input
type="text"
@@ -664,8 +780,8 @@
class="form-control"
/>
<span class="input-group-text"
>Hz</span
>
>Hz
</span>
</div>
</div>
</div>
@@ -674,8 +790,8 @@
<label
for="action.speed"
class="form-label"
>Predefined speeds</label
>
>Predefined speeds
</label>
<select
class="form-select form-select"
name="action.speed"
@@ -710,8 +826,8 @@
<label
for="lora.signalBandwidth"
class="form-label"
>Bandwidth</label
>
>Bandwidth
</label>
<div class="input-group">
<select
class="form-select form-select"
@@ -735,8 +851,8 @@
<label
for="lora.spreadingFactor"
class="form-label"
>Spreading Factor</label
>
>Spreading Factor
</label>
<select
class="form-select form-select"
name="lora.spreadingFactor"
@@ -760,16 +876,15 @@
<div class="col-6">
<label
for="lora.codingRate4"
class="form-label"
>Coding Rate</label
>
class="form-label">
Coding Rate
</label>
<select
class="form-select form-select"
name="lora.codingRate4"
id="lora.codingRate4"
required=""
>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
@@ -779,9 +894,9 @@
<div class="col-6">
<label
for="lora.power"
class="form-label"
>Power</label
>
class="form-label">
Power
</label>
<div class="input-group">
<input
type="number"
@@ -925,7 +1040,15 @@
</svg>
Battery
</h5>
<small>Battery Monitor & Health</small>
<small>
Battery Monitor & Health
<br>
<br>
Max Voltage on input pin is 3.3V.
<br>
<br>
Calculate voltage divider accordingly.
</small>
</div>
<div class="col-9 mt-2">
<div class="row mt-2">
@@ -946,14 +1069,15 @@
<div class="form-check form-switch">
<input
type="checkbox"
name="battery.sendExternalVoltage"
id="battery.sendExternalVoltage"
name="battery.sendVoltageAsTelemetry"
id="battery.sendVoltageAsTelemetry"
class="form-check-input"
/>
<label
for="battery.sendExternalVoltage"
for="battery.sendVoltageAsTelemetry"
class="form-label"
>Send External Voltage</label
style="font-style: italic;"
>(Send Voltage As Telemetry)</label
>
</div>
<div class="form-check form-switch mt-3">
@@ -981,7 +1105,7 @@
placeholder="3.0"
class="form-control"
step="0.1"
min="3.0"
min="2.9"
max="3.7"
/>
<span class="input-group-text"
@@ -991,21 +1115,20 @@
</div>
</div>
<div class="col-6">
<div class="form-floating col-7">
<div class="form-check form-switch">
<input
type="text"
name="battery.externalVoltagePin"
id="battery.externalVoltagePin"
value="34"
class="form-control"
type="checkbox"
name="battery.sendExternalVoltage"
id="battery.sendExternalVoltage"
class="form-check-input"
/>
<label
for="battery.externalVoltagePin"
for="battery.sendExternalVoltage"
class="form-label"
>External Voltage Pin</label
>Send External Voltage</label
>
</div>
<div class="form-check form-switch mt-4">
<div class="form-check form-switch mt-5">
<input
type="checkbox"
name="battery.monitorExternalVoltage"
@@ -1038,6 +1161,52 @@
>
</div>
</div>
<div class="form-floating col-7 mt-3">
<input
type="text"
name="battery.externalVoltagePin"
id="battery.externalVoltagePin"
value="34"
class="form-control"
/>
<label
for="battery.externalVoltagePin"
class="form-label"
>External Voltage Pin</label
>
</div>
<div class="col">
<label for="battery.voltageDividerR1" class="form-label">External Voltage divider R1</label>
<div class="input-group">
<input
type="number"
name="battery.voltageDividerR1"
id="battery.voltageDividerR1"
placeholder="100.0"
class="form-control"
step="0.1"
min="1"
max="1000"
/>
<span class="input-group-text">kOhm</span>
</div>
</div>
<div class="col">
<label for="battery.voltageDividerR2" class="form-label">External Voltage divider R2</label>
<div class="input-group">
<input
type="number"
name="battery.voltageDividerR2"
id="battery.voltageDividerR2"
placeholder="27.0"
class="form-control"
step="0.1"
min="1"
max="1000"
/>
<span class="input-group-text">kOhm</span>
</div>
</div>
</div>
</div>
</div>
@@ -1059,9 +1228,9 @@
d="M3.05 3.05a7 7 0 0 0 0 9.9.5.5 0 0 1-.707.707 8 8 0 0 1 0-11.314.5.5 0 0 1 .707.707m2.122 2.122a4 4 0 0 0 0 5.656.5.5 0 1 1-.708.708 5 5 0 0 1 0-7.072.5.5 0 0 1 .708.708m5.656-.708a.5.5 0 0 1 .708 0 5 5 0 0 1 0 7.072.5.5 0 1 1-.708-.708 4 4 0 0 0 0-5.656.5.5 0 0 1 0-.708m2.122-2.12a.5.5 0 0 1 .707 0 8 8 0 0 1 0 11.313.5.5 0 0 1-.707-.707 7 7 0 0 0 0-9.9.5.5 0 0 1 0-.707zM6 8a2 2 0 1 1 2.5 1.937V15.5a.5.5 0 0 1-1 0V9.937A2 2 0 0 1 6 8"
/>
</svg>
Telemetry
WX Telemetry
</h5>
<small>Define the telemetry</small>
<small>Define Wx telemetry</small>
</div>
<div class="col-9 mt-2">
<div class="row">
@@ -1069,18 +1238,16 @@
<div class="form-check form-switch">
<input
type="checkbox"
name="bme.active"
id="bme.active"
name="wxsensor.active"
id="wxsensor.active"
class="form-check-input"
/>
<label
for="bme.active"
for="wxsensor.active"
class="form-label"
><b>Activate Wx Telemetry</b>
<small
>Requires a BME/BMP280 or
BME680 sensor
installed</small
>Requires a BME/BMP280, BME680 or Si7021 sensor.</small
></label
>
</div>
@@ -1088,14 +1255,14 @@
</div>
<div class="row mt-3">
<div class="col-6">
<label for="bme.heightCorrection" class="form-label"
<label for="wxsensor.heightCorrection" class="form-label"
>Height Correction (Above Sea-Level)</label
>
<div class="input-group">
<input
type="number"
name="bme.heightCorrection"
id="bme.heightCorrection"
name="wxsensor.heightCorrection"
id="wxsensor.heightCorrection"
placeholder="0"
class="form-control"
step="1"
@@ -1107,14 +1274,14 @@
</div>
</div>
<div class="col-6">
<label for="bme.temperatureCorrection" class="form-label"
<label for="wxsensor.temperatureCorrection" class="form-label"
>Temperature Correction</label
>
<div class="input-group">
<input
type="number"
name="bme.temperatureCorrection"
id="bme.temperatureCorrection"
name="wxsensor.temperatureCorrection"
id="wxsensor.temperatureCorrection"
placeholder="0.0"
class="form-control"
step="0.1"
@@ -1178,7 +1345,7 @@
type="text"
name="syslog.server"
id="syslog.server"
placeholder="192.168.0.100"
placeholder="lora.link9.net"
class="form-control"
disabled
/>
@@ -1193,7 +1360,7 @@
type="text"
name="syslog.port"
id="syslog.port"
placeholder="514"
placeholder="1514"
class="form-control"
disabled
/>
@@ -1339,7 +1506,7 @@
type="number"
name="other.rebootModeTime"
id="other.rebootModeTime"
placeholder="0"
placeholder="6"
class="form-control"
step="6"
min="6"
@@ -1379,10 +1546,10 @@
d="M8.5 5.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0"
/>
</svg>
Auto AP
WiFi Auto AP
</h5>
<small
>Add your password and power off timeout to
>Add your password and WiFi AP timeout to
auto access point. Auto AP will start if
there is no WiFi connection. Timeout will
count from startup or last client
@@ -1407,24 +1574,24 @@
</div>
<div class="col-12 mt-3">
<label
for="wifi.autoAP.powerOff"
for="wifi.autoAP.timeout"
class="form-label"
>Power off timeout
>WiFi AP timeout to search again for available WiFi's
<small>(in minutes)</small></label
>
<input
type="number"
name="wifi.autoAP.powerOff"
id="wifi.autoAP.powerOff"
name="wifi.autoAP.timeout"
id="wifi.autoAP.timeout"
class="form-control"
placeholder="15"
placeholder="10"
required=""
step="1"
min="0"
/>
<div class="form-text">
Set to <strong>0</strong> if you don't
want this option.
want WiFi AP to stop.
</div>
</div>
</div>
@@ -1481,6 +1648,183 @@
</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-cloud-upload-fill"
viewBox="0 0 16 16"
>
<path
fill-rule="evenodd"
d="M8 0a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 4.095 0 5.555 0 7.318 0 9.366 1.708 11 3.781 11H7.5V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11h4.188C14.502 11 16 9.57 16 7.773c0-1.636-1.242-2.969-2.834-3.194C12.923 1.999 10.69 0 8 0m-.5 14.5V11h1v3.5a.5.5 0 0 1-1 0"
/>
</svg>
Admin
</h5>
<small
>Set your username and password to allow
access to the web interface.</small
>
</div>
<div class="col-lg-9 col-sm-12">
<div class="row">
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="webadmin.active"
id="webadmin.active"
class="form-check-input"
/>
<label
for="webadmin.active"
class="form-label"
>Web interface authentication</label
>
</div>
</div>
</div>
<div class="col-12">
<label for="webadmin.username" class="form-label"
>Username</label
>
<input
type="text"
name="webadmin.username"
id="webadmin.username"
class="form-control"
value="admin"
required=""
/>
</div>
<div class="col-12 mt-3">
<label for="webadmin.password" class="form-label"
>Password</label
>
<input
type="password"
name="webadmin.password"
id="webadmin.password"
class="form-control"
/>
</div>
</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-cloud-upload-fill"
viewBox="0 0 16 16"
>
<path
fill-rule="evenodd"
d="M8 0a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 4.095 0 5.555 0 7.318 0 9.366 1.708 11 3.781 11H7.5V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11h4.188C14.502 11 16 9.57 16 7.773c0-1.636-1.242-2.969-2.834-3.194C12.923 1.999 10.69 0 8 0m-.5 14.5V11h1v3.5a.5.5 0 0 1-1 0"
/>
</svg>
Remote Management
</h5>
<small
>Manage Station via APRS Messages. Leave empty to disable!
</small>
</div>
<div class="col-lg-9 col-sm-12">
<div class="col-12">
<label
for="remoteManagement.managers"
class="form-label"
>Callsign-SSID of Managers, space separated, trailing * wildcard allowed (ex: AB1CDE-9, AB1CDE*)</label
>
<div class="input-group">
<input
type="text"
name="remoteManagement.managers"
id="remoteManagement.managers"
class="form-control"
/>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-check form-switch">
<input
type="checkbox"
name="remoteManagement.rfOnly"
id="remoteManagement.rfOnly"
class="form-check-input"
/>
<label
for="remoteManagement.rfOnly"
class="form-label"
>Managers commands only via RF (not APRS-IS)</label
>
</div>
</div>
</div>
</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-cloud-upload-fill"
viewBox="0 0 16 16"
>
<path
fill-rule="evenodd"
d="M8 0a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 4.095 0 5.555 0 7.318 0 9.366 1.708 11 3.781 11H7.5V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11h4.188C14.502 11 16 9.57 16 7.773c0-1.636-1.242-2.969-2.834-3.194C12.923 1.999 10.69 0 8 0m-.5 14.5V11h1v3.5a.5.5 0 0 1-1 0"
/>
</svg>
NTP
</h5>
<small
>Set your GMT Time Zone.
</small>
</div>
<div class="col-lg-9 col-sm-12">
<div class="col-12">
<label
for="ntp.gmtCorrection"
class="form-label"
>GMT Time Correction for accurate Local Time</label
>
<div class="input-group">
<input
type="number"
name="ntp.gmtCorrection"
id="ntp.gmtCorrection"
placeholder="0"
class="form-control"
step="0.25"
min="-23.75"
max="23.75"
/>
<span class="input-group-text"
>hours</span
>
</div>
</div>
</div>
</div>
<hr />
<div class="row my-5 d-flex align-items-top">
<div class="col-lg-3 col-sm-12">
<h5>
@@ -1508,7 +1852,7 @@
<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 Digirepeater Mode and after 15 min check if WiFi available and return to "only" iGate Mode.
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"
@@ -1519,50 +1863,10 @@
<label
for="other.backupDigiMode"
class="form-label"
>Backup Digirepeater Mode</label
>Backup Digipeater Mode</label
>
</div>
</div>
<div class="col-12">
<div class="form-check form-switch">
<div class="form-text">
WiFi disabled. Sleep mode. Best for solar Digi with SX126X.
</div>
<input
type="checkbox"
name="other.lowPowerMode"
id="other.lowPowerMode"
class="form-check-input"
/>
<label
for="other.lowPowerMode"
class="form-label"
>Low power mode</label
>
</div>
</div>
<div class="col-12 mt-3">
<label
for="other.lowVoltageCutOff"
class="form-label"
>Low voltage cut off <small>(Deep sleep below specific voltage)</small></label
>
<input
type="text"
name="other.lowVoltageCutOff"
id="other.lowVoltageCutOff"
placeholder="0"
min="0"
step="0.01"
class="form-control"
/>
<span class="input-group-text"
>Volts</span
>
<div class="form-text">
MCU will deep sleep when below provided battery voltage to save power. Set to <strong>0</strong> if you don't want this option. <u>Please calibrate your voltage reading first!</u>
</div>
</div>
</div>
</div>
</div>
@@ -1702,4 +2006,4 @@
</body>
<script src="/bootstrap.js"></script>
<script src="/script.js"></script>
</html>
</html>

View File

@@ -79,7 +79,7 @@ function loadSettings(settings) {
document.getElementById("beacon.path").value = settings.beacon.path;
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
document.getElementById("beacon.overlay").value = settings.beacon.overlay;
document.getElementById("personalNote").value = settings.personalNote;
document.getElementById("action.symbol").value = settings.beacon.overlay + settings.beacon.symbol;
document.querySelector(".list-networks").innerHTML = "";
@@ -134,8 +134,15 @@ function loadSettings(settings) {
document.getElementById("beacon.sendViaAPRSIS").checked = settings.beacon.sendViaAPRSIS;
document.getElementById("beacon.sendViaRF").checked = settings.beacon.sendViaRF;
document.getElementById("beacon.gpsActive").checked = settings.beacon.gpsActive;
document.getElementById("beacon.gpsAmbiguity").checked = settings.beacon.gpsAmbiguity;
// Black List
document.getElementById("blacklist").value = settings.blacklist;
// Digi
document.getElementById("digi.mode").value = settings.digi.mode;
document.getElementById("digi.ecoMode").checked = settings.digi.ecoMode;
// LoRa
document.getElementById("lora.txFreq").value = settings.lora.txFreq;
@@ -162,13 +169,16 @@ function loadSettings(settings) {
document.getElementById("battery.internalSleepVoltage").value = settings.battery.internalSleepVoltage.toFixed(1);
document.getElementById("battery.sendExternalVoltage").checked = settings.battery.sendExternalVoltage;
document.getElementById("battery.externalVoltagePin").value = settings.battery.externalVoltagePin;
document.getElementById("battery.voltageDividerR1").value = settings.battery.voltageDividerR1.toFixed(1);
document.getElementById("battery.voltageDividerR2").value = settings.battery.voltageDividerR2.toFixed(1);
document.getElementById("battery.monitorExternalVoltage").checked = settings.battery.monitorExternalVoltage;
document.getElementById("battery.externalSleepVoltage").value = settings.battery.externalSleepVoltage.toFixed(1);
document.getElementById("battery.sendVoltageAsTelemetry").checked = settings.battery.sendVoltageAsTelemetry;
// TELEMETRY BME/WX
document.getElementById("bme.active").checked = settings.bme.active;
document.getElementById("bme.heightCorrection").value = settings.bme.heightCorrection;
document.getElementById("bme.temperatureCorrection").value = settings.bme.temperatureCorrection.toFixed(1);
// TELEMETRY WX SENSOR
document.getElementById("wxsensor.active").checked = settings.wxsensor.active;
document.getElementById("wxsensor.heightCorrection").value = settings.wxsensor.heightCorrection;
document.getElementById("wxsensor.temperatureCorrection").value = settings.wxsensor.temperatureCorrection.toFixed(1);
// SYSLOG
document.getElementById("syslog.active").checked = settings.syslog.active;
@@ -193,17 +203,26 @@ function loadSettings(settings) {
// WiFi Auto AP
document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password;
document.getElementById("wifi.autoAP.powerOff").value = settings.wifi.autoAP.powerOff;
document.getElementById("wifi.autoAP.timeout").value = settings.wifi.autoAP.timeout;
// OTA
document.getElementById("ota.username").value = settings.ota.username;
document.getElementById("ota.password").value = settings.ota.password;
// Webadmin
document.getElementById("webadmin.active").checked = settings.webadmin.active;
document.getElementById("webadmin.username").value = settings.webadmin.username;
document.getElementById("webadmin.password").value = settings.webadmin.password;
// NTP
document.getElementById("ntp.gmtCorrection").value = settings.ntp.gmtCorrection;
// Experimental
document.getElementById("other.backupDigiMode").checked = settings.other.backupDigiMode;
document.getElementById("other.lowPowerMode").checked = settings.other.lowPowerMode;
document.getElementById("other.lowVoltageCutOff").value = settings.other.lowVoltageCutOff || 0
// Management over APRS
document.getElementById("remoteManagement.managers").value = settings.remoteManagement.managers;
document.getElementById("remoteManagement.rfOnly").checked = settings.remoteManagement.rfOnly;
updateImage();
refreshSpeedStandard();
@@ -234,9 +253,7 @@ document.getElementById('reboot').addEventListener('click', function (e) {
showToast("Your device will be rebooted in a while");
});
const bmeCheckbox = document.querySelector("input[name='bme.active']");
const stationModeSelect = document.querySelector("select[name='stationMode']");
const wxsensorCheckbox = document.querySelector("input[name='wxsensor.active']");
function updateImage() {
const value = document.getElementById("beacon.overlay").value + document.getElementById("beacon.symbol").value;
@@ -271,8 +288,23 @@ function toggleFields() {
'input[name="battery.externalVoltagePin"]'
);
externalVoltagePinInput.disabled =
!sendExternalVoltageCheckbox.checked;
externalVoltagePinInput.disabled = !sendExternalVoltageCheckbox.checked;
voltageDividerR1.disabled = !sendExternalVoltageCheckbox.checked;
voltageDividerR2.disabled = !sendExternalVoltageCheckbox.checked;
const WebadminCheckbox = document.querySelector(
'input[name="webadmin.active"]'
);
const WebadminUsername = document.querySelector(
'input[name="webadmin.username"]'
);
const WebadminPassword = document.querySelector(
'input[name="webadmin.password"]'
);
WebadminUsername.disabled = !WebadminCheckbox.checked;
WebadminPassword.disabled = !WebadminCheckbox.checked;
}
const sendExternalVoltageCheckbox = document.querySelector(
@@ -282,8 +314,34 @@ const externalVoltagePinInput = document.querySelector(
'input[name="battery.externalVoltagePin"]'
);
const voltageDividerR1 = document.querySelector(
'input[name="battery.voltageDividerR1"]'
);
const voltageDividerR2 = document.querySelector(
'input[name="battery.voltageDividerR2"]'
);
sendExternalVoltageCheckbox.addEventListener("change", function () {
externalVoltagePinInput.disabled = !this.checked;
voltageDividerR1.disabled = !this.checked;
voltageDividerR2.disabled = !this.checked;
});
const WebadminCheckbox = document.querySelector(
'input[name="webadmin.active"]'
);
const WebadminUsername = document.querySelector(
'input[name="webadmin.username"]'
);
const WebadminPassword = document.querySelector(
'input[name="webadmin.password"]'
);
WebadminCheckbox.addEventListener("change", function () {
WebadminUsername.disabled = !this.checked;
WebadminPassword.disabled = !this.checked;
});
document.querySelector(".new button").addEventListener("click", function () {
@@ -457,13 +515,9 @@ function loadReceivedPackets(packets) {
packets.forEach((packet) => {
const element = document.createElement("tr");
date.setTime(packet.millis);
const p = date.toUTCString().split(' ')
element.innerHTML = `
<td>${p[p.length-2]}</td>
<td>${packet.rxTime}</td>
<td>${packet.packet}</td>
<td>${packet.RSSI}</td>
<td>${packet.SNR}</td>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 122 KiB

BIN
images/Web004-BlackList.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 130 KiB

BIN
images/Web015-Admin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
images/Web015-Manager.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
images/Web016-NTP.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

View File

@@ -3,6 +3,7 @@
#include <Arduino.h>
namespace A7670_Utils {
bool checkModemOn();

View File

@@ -1,39 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@@ -8,15 +8,20 @@ namespace APRS_IS_Utils {
void upload(const String& line);
void connect();
void checkStatus();
String checkForStartingBytes(const String& packet);
String buildPacketToUpload(const String& packet);
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType);
bool processReceivedLoRaMessage(const String& sender, const String& packet);
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty);
void processLoRaPacket(const String& packet);
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType);
void processAPRSISPacket(const String& packet);
void listenAPRSIS();
void firstConnection();
}
#endif

22
include/battery_utils.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef BATTERY_UTILS_H_
#define BATTERY_UTILS_H_
#include <Arduino.h>
namespace BATTERY_Utils {
void adcCalibration();
void adcCalibrationCheck();
void setup();
float checkInternalVoltage();
float checkExternalVoltage();
void startupBatteryHealth();
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType);
String generateEncodedTelemetry();
}
#endif

View File

@@ -5,6 +5,7 @@
#include <vector>
#include <FS.h>
class WiFi_AP {
public:
String ssid;
@@ -14,7 +15,7 @@ public:
class WiFi_Auto_AP {
public:
String password;
int powerOff;
int timeout;
};
class BEACON {
@@ -28,6 +29,8 @@ public:
String path;
bool sendViaRF;
bool sendViaAPRSIS;
bool gpsActive;
bool gpsAmbiguity;
};
class APRS_IS {
@@ -44,9 +47,9 @@ public:
class DIGI {
public:
int mode;
int ecoMode; // 0 = Not Active | 1 = Ultra EcoMode | 2 = Not Active (WiFi OFF, Serial ON)
};
class LoraModule {
public:
long txFreq;
@@ -75,9 +78,12 @@ public:
int externalVoltagePin;
bool monitorExternalVoltage;
float externalSleepVoltage;
float voltageDividerR1;
float voltageDividerR2;
bool sendVoltageAsTelemetry;
};
class BME {
class WXSENSOR {
public:
bool active;
int heightCorrection;
@@ -104,16 +110,33 @@ public:
String password;
};
class WEBADMIN {
public:
bool active;
String username;
String password;
};
class NTP {
public:
float gmtCorrection;
};
class REMOTE_MANAGEMENT {
public:
String managers;
bool rfOnly;
};
class Configuration {
public:
bool reload; // ?
String callsign;
int rememberStationTime;
bool lowPowerMode;
double lowVoltageCutOff;
bool backupDigiMode;
bool rebootMode;
int rebootModeTime;
String personalNote;
String blacklist;
std::vector<WiFi_AP> wifiAPs;
WiFi_Auto_AP wifiAutoAP;
BEACON beacon;
@@ -122,14 +145,16 @@ public:
LoraModule loramodule;
Display display;
BATTERY battery;
BME bme;
WXSENSOR wxsensor;
SYSLOG syslog;
TNC tnc;
OTA ota;
WEBADMIN webadmin;
NTP ntp;
REMOTE_MANAGEMENT remoteManagement;
void init();
void writeFile();
void check();
Configuration();
private:

View File

@@ -6,9 +6,10 @@
namespace DIGI_Utils {
String buildPacket(const String& path, const String& packet, bool thirdParty);
String generateDigiRepeatedPacket(const String& packet, bool thirdParty);
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq);
String generateDigipeatedPacket(const String& packet, bool thirdParty);
void processLoRaPacket(const String& packet);
void checkEcoMode();
}

14
include/display.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef DISPLAY_H_
#define DISPLAY_H_
#include <Arduino.h>
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
void displaySetup();
void displayToggle(bool toggle);
void displayShow(const String& header, const String& line1, const String& line2, const String& line3, int wait = 0);
void displayShow(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6, int wait = 0);
#endif

View File

@@ -5,16 +5,19 @@
namespace GPS_Utils {
String getiGateLoRaBeaconPacket();
char *ax25_base91enc(char *s, uint8_t n, uint32_t v);
String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol);
void generateBeaconFirstPart();
void generateBeacons();
double calculateDistanceCourse(double latitude, double longitude);
String decodeEncodedGPS(const String& packet);
String getReceivedGPS(const String& packet);
String getDistanceAndComment(const String& packet);
void setup();
void getData();
}
#endif

View File

@@ -3,6 +3,7 @@
#include <Arduino.h>
String encodeAddressAX25(String tnc2Address);
String decodeAddressAX25(const String& ax25Address, bool& isLast, bool isRelay);

View File

@@ -8,11 +8,12 @@ namespace LoRa_Utils {
void setup();
void sendNewPacket(const String& newPacket);
//String packetSanitization(const String& packet);
String receivePacketFromSleep();
String receivePacket();
void changeFreqTx();
void changeFreqRx();
void startReceive(); // ???
void wakeRadio();
//void startReceive();
void sleepRadio();
}

15
include/ntp_utils.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef NTP_UTILS_H_
#define NTP_UTILS_H_
#include <Arduino.h>
namespace NTP_Utils {
void setup();
void update();
String getFormatedTime();
}
#endif

View File

@@ -14,6 +14,8 @@ namespace POWER_Utils {
double getBatteryVoltage();
bool isBatteryConnected();
void activateMeasurement();
void activateGPS();
void deactivateGPS();
void activateLoRa();
void deactivateLoRa();
bool begin(TwoWire &port);

13
include/query_utils.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef QUERY_UTILS_H_
#define QUERY_UTILS_H_
#include <Arduino.h>
namespace QUERY_Utils {
String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty);
}
#endif

14
include/sleep_utils.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef SLEEP_UTILS_H_
#define SLEEP_UTILS_H_
#include <Arduino.h>
namespace SLEEP_Utils {
void setup();
void checkWakeUpFlag();
void startSleeping();
}
#endif

36
include/station_utils.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef STATION_UTILS_H_
#define STATION_UTILS_H_
#include <Arduino.h>
struct Packet25SegBuffer {
uint32_t receivedTime;
String station;
String payload;
};
struct LastHeardStation {
uint32_t lastHeardTime;
String station;
};
namespace STATION_Utils {
void loadBlacklistAndManagers();
bool isBlacklisted(const String& callsign);
bool isManager(const String& callsign);
bool checkObjectTime(const String& packet);
void deleteNotHeard();
void updateLastHeard(const String& station);
bool wasHeard(const String& station);
void clean25SegBuffer();
bool check25SegBuffer(const String& station, const String& textMessage);
void processOutputPacketBufferUltraEcoMode();
void processOutputPacketBuffer();
void addToOutputPacketBuffer(const String& packet);
}
#endif

View File

@@ -3,6 +3,7 @@
#include <Arduino.h>
namespace TNC_Utils {
void setup();

View File

@@ -3,9 +3,10 @@
#include <Arduino.h>
class ReceivedPacket {
public:
long millis;
String rxTime;
String packet;
int RSSI;
float SNR;

View File

@@ -13,10 +13,6 @@ namespace WEB_Utils {
void handleNotFound(AsyncWebServerRequest *request);
void handleStatus(AsyncWebServerRequest *request);
void handleHome(AsyncWebServerRequest *request);
//void handleReadConfiguration(AsyncWebServerRequest *request);
//void handleWriteConfiguration(AsyncWebServerRequest *request);
void handleStyle(AsyncWebServerRequest *request);
void handleScript(AsyncWebServerRequest *request);
void handleBootstrapStyle(AsyncWebServerRequest *request);

View File

@@ -9,7 +9,7 @@ namespace WIFI_Utils {
void checkWiFi();
void startAutoAP();
void startWiFi();
void checkIfAutoAPShouldPowerOff();
void checkAutoAPTimeout();
void setup();
}

23
include/wx_utils.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef WX_UTILS_H_
#define WX_UTILS_H_
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_BME680.h>
#include "Adafruit_Si7021.h"
#include <Arduino.h>
namespace WX_Utils {
void getWxModuleAddres();
void setup();
String generateTempString(const float sensorTemp);
String generateHumString(const float sensorHum);
String generatePresString(const float sensorPres);
String readDataSensor();
}
#endif

View File

@@ -1,39 +0,0 @@
@echo off
echo Loading...
where /q python.exe
if %errorlevel% neq 0 (
echo "Python is not installed. Please install it and try again."
exit /b
)
where /q pip
if %errorlevel% neq 0 (
echo "pip is not installed. Please install it and try again."
exit /b
)
pip show pyserial >nul 2>&1
if %errorlevel% neq 0 (
echo "Installing pyserial..."
pip install pyserial
)
echo Your firmware will be upgraded without factory reset.
echo:
echo IF THIS IS YOUR FIRST FLASH ON THIS BOARD PLEASE USE install_with_factory_reset.bat INSTEAD!
echo:
echo Available COM ports:
python.exe -c "import serial.tools.list_ports; print('\n'.join([str(c) for c in serial.tools.list_ports.comports()]))"
echo:
set /p port="Enter COM port (for example COM5): "
python.exe ./bin/esptool/esptool.py --chip esp32 --port "%port%" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 firmware/bootloader.bin 0x8000 firmware/partitions.bin 0xe000 firmware/boot_app0.bin 0x10000 firmware/firmware.bin
pause

View File

@@ -1,15 +0,0 @@
#!/bin/bash
echo "Your firmware will be upgraded without factory reset."
echo "IF THIS IS YOUR FIRST FLASH ON THIS BOARD PLEASE USE install_with_factory_reset.sh INSTEAD!"
read -p "Enter COM port (for example /dev/ttyS5): " port
PYTHON_CMD=python
if command -v python3 &> /dev/null
then
PYTHON_CMD=python3
fi
PYTHON_CMD ./bin/esptool/esptool.py --chip esp32 --port "$port" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 firmware/bootloader.bin 0x8000 firmware/partitions.bin 0xe000 firmware/boot_app0.bin 0x10000 firmware/firmware.bin
echo "Firmware flashed"

View File

@@ -1,44 +0,0 @@
@echo off
echo Loading...
where /q python.exe
if %errorlevel% neq 0 (
echo "Python is not installed. Please install it and try again."
exit /b
)
where /q pip
if %errorlevel% neq 0 (
echo "pip is not installed. Please install it and try again."
exit /b
)
pip show pyserial >nul 2>&1
if %errorlevel% neq 0 (
echo "Installing pyserial..."
pip install pyserial
)
echo Your current configuration will be LOST!!!
echo Your current configuration will be LOST!!!
echo Your current configuration will be LOST!!!
echo:
echo If you already have this board flashed with our firmware please use install_upgrade.bat instead!
echo:
echo Available COM ports:
python.exe -c "import serial.tools.list_ports; print('\n'.join([str(c) for c in serial.tools.list_ports.comports()]))"
echo:
set /p port="Enter COM port (for example COM5): "
python.exe bin/esptool/esptool.py --chip esp32 --port "%port%" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 2686976 firmware/spiffs.bin
python.exe bin/esptool/esptool.py --chip esp32 --port "%port%" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 firmware/bootloader.bin 0x8000 firmware/partitions.bin 0xe000 firmware/boot_app0.bin 0x10000 firmware/firmware.bin
pause

View File

@@ -1,17 +0,0 @@
#!/bin/bash
echo "Your firmware will be upgraded without factory reset."
echo "IF THIS IS YOUR FIRST FLASH ON THIS BOARD PLEASE USE install_with_factory_reset.sh INSTEAD!"
read -p "Enter COM port (for example /dev/ttyS5): " port
PYTHON_CMD=python
if command -v python3 &> /dev/null
then
PYTHON_CMD=python3
fi
$PYTHON_CMD ./bin/esptool/esptool.py --chip esp32 --port "$port" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 2686976 firmware/spiffs.bin
$PYTHON_CMD ./bin/esptool/esptool.py --chip esp32 --port "$port" --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 firmware/bootloader.bin 0x8000 firmware/partitions.bin 0xe000 firmware/boot_app0.bin 0x10000 firmware/firmware.bin
echo "Firmware flashed"

View File

@@ -11,6 +11,10 @@
[platformio]
default_envs = ttgo-lora32-v21
extra_configs =
common_settings.ini
variants/*/platformio.ini
[env]
platform = espressif32 @ 6.7.0
board_build.partitions = min_spiffs.csv
@@ -22,376 +26,7 @@ board_build.embed_files =
data_embed/script.js.gz
data_embed/bootstrap.css.gz
data_embed/bootstrap.js.gz
data_embed/favicon.png.gz
extra_scripts =
pre:tools/compress.py
debug_tool = esp-prog
[common]
lib_deps =
jgromes/RadioLib @ 6.6.0
mikalhart/TinyGPSPlus @ 1.0.3
bblanchon/ArduinoJson @ 6.21.3
adafruit/Adafruit Unified Sensor @ 1.1.14
adafruit/Adafruit BME280 Library @ 2.2.4
adafruit/Adafruit BMP280 Library @ 2.6.8
adafruit/Adafruit BME680 Library @ 2.0.4
adafruit/Adafruit Si7021 Library @ 1.5.3
ayushsharma82/ElegantOTA @ 3.1.1
ottowinter/ESPAsyncWebServer-esphome @ 3.2.2
esphome/AsyncTCP-esphome @ 2.1.1
[env:ttgo-lora32-v21]
board = ttgo-lora32-v21
build_flags =
-Werror -Wall
-DTTGO_T_LORA32_V2_1
-DHAS_SX1278
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:ttgo-lora32-v21_915]
board = ttgo-lora32-v21
build_flags =
-Werror -Wall
-DTTGO_T_LORA32_V2_1_915
-DHAS_SX1276
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:heltec-lora32-v2]
board = ttgo-lora32-v21
build_flags =
-Werror -Wall
-DHELTEC_V2
-DHAS_SX1278
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:heltec_wifi_lora_32_V3]
board = heltec_wifi_lora_32_V3
board_build.mcu = esp32s3
build_flags =
-Werror -Wall
-DHELTEC_V3
-DHAS_SX1262
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:heltec_wireless_stick]
board = heltec_wifi_lora_32_V3
board_build.mcu = esp32s3
build_flags =
-Werror -Wall
-DHELTEC_WS
-DHAS_SX1262
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:heltec_wireless_stick_lite_v3]
board = esp32-s3-devkitc-1
board_build.mcu = esp32s3
build_flags =
-Werror -Wall
-DHELTEC_WSL_V3
-DHAS_SX1262
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
[env:ESP32_DIY_LoRa]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_LoRa
-DHAS_SX1278
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:ESP32_DIY_LoRa_915]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_LoRa_915
-DHAS_SX1276
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:ESP32_DIY_1W_LoRa]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_1W_LoRa
-DHAS_SX1268
-DHAS_1W_LORA
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:ESP32_DIY_1W_LoRa_915]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_1W_LoRa_915
-DHAS_SX1262
-DHAS_1W_LORA
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:ttgo-t-beam-v1_2]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_2
-DHAS_SX1278
-DHAS_AXP2101
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ttgo-t-beam-v1_2_915]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_2_915
-DHAS_SX1276
-DHAS_AXP2101
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ttgo-t-beam-v1]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_0
-DHAS_SX1278
-DHAS_AXP192
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ttgo-t-beam-v1_915]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_0_915
-DHAS_SX1276
-DHAS_AXP192
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ttgo-t-beam-v1_SX1268]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_0_SX1268
-DHAS_SX1268
-DHAS_AXP192
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ttgo-t-beam-v1_2_SX1262]
board = ttgo-t-beam
build_flags =
-Werror -Wall
-DTTGO_T_Beam_V1_2_SX1262
-DHAS_SX1262
-DHAS_AXP2101
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
lewisxhe/XPowersLib @ 0.2.4
[env:ESP32_DIY_LoRa_A7670]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_LoRa_A7670
-DHAS_SX1278
-DHAS_A7670
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
vshymanskyy/TinyGSM @ 0.12.0
vshymanskyy/StreamDebugger @ 1.0.1
[env:ESP32_DIY_LoRa_A7670_915]
board = esp32dev
build_flags =
-Werror -Wall
-DESP32_DIY_LoRa_A7670_915
-DHAS_SX1276
-DHAS_A7670
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
vshymanskyy/TinyGSM @ 0.12.0
vshymanskyy/StreamDebugger @ 1.0.1
[env:heltec_wireless_tracker]
board = esp32-s3-devkitc-1
board_build.mcu = esp32s3
build_flags =
-Werror -Wall
-DHELTEC_WIRELESS_TRACKER
-DHAS_SX1262
-DHAS_TFT
-D USER_SETUP_LOADED
-D TFT_WIDTH=80
-D TFT_HEIGHT=160
-D ST7735_DRIVER
-D ST7735_GREENTAB160x80
-D TFT_RGB_ORDER=TFT_BGR
-D TFT_MOSI=42
-D TFT_SCLK=41
-D TFT_CS=38
-D TFT_DC=40
-D TFT_RST=39
-D TFT_BL=21
-D TFT_BACKLIGHT_ON=1
-D TOUCH_CS=-1
-D LOAD_GLCD
-D LOAD_FONT2
-D LOAD_FONT4
-D LOAD_FONT6
-D LOAD_FONT7
-D LOAD_FONT8
-D SPI_FREQUENCY=27000000
-D USE_HSPI_PORT
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
bodmer/TFT_eSPI @ 2.5.43
[env:heltec_ht-ct62]
board = heltec_wireless_stick_lite
board_build.mcu = esp32c3
build_flags =
-Werror -Wall
-DHELTEC_HTCT62
-DHAS_SX1262
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:OE5HWN_MeshCom]
board = esp32dev
build_flags =
-Werror -Wall
-DOE5HWN_MeshCom
-DHAS_SX1268
-DHAS_1W_LORA
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:WEMOS-LOLIN32-OLED-DIY]
board = lolin32
build_flags =
-Werror -Wall
-DWEMOS_LOLIN32_OLED_DIY_LoRa
-DHAS_SX1278
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:WEMOS-D1-R32-RA02]
board = wemos_d1_uno32
build_flags =
-Werror -Wall
-DWEMOS_D1_R32_RA02
-DHAS_SX1278
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:esp32c3_DIY_1W_LoRa]
board = esp32-c3-devkitm-1
board_build.mcu = esp32c3
build_flags =
-Werror -Wall
-DESP32C3_DIY_1W_LoRa
-DHAS_SX1268
-DHAS_1W_LORA
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
[env:esp32c3_DIY_1W_LoRa_915]
board = esp32-c3-devkitm-1
board_build.mcu = esp32c3
build_flags =
-Werror -Wall
-DESP32C3_DIY_1W_LoRa_915
-DHAS_SX1262
-DHAS_1W_LORA
-DARDUINO_USB_MODE=1
-DARDUINO_USB_CDC_ON_BOOT=1
-DELEGANTOTA_USE_ASYNC_WEBSERVER=1
lib_deps =
${common.lib_deps}
adafruit/Adafruit GFX Library @ 1.11.9
adafruit/Adafruit SSD1306 @ 2.5.10
debug_tool = esp-prog

View File

@@ -1,11 +1,12 @@
#include "configuration.h"
#include "aprs_is_utils.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "A7670_utils.h"
#include "lora_utils.h"
#include "display.h"
#include "utils.h"
#ifdef HAS_A7670
#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
@@ -33,7 +34,7 @@
bool checkModemOn() {
bool modemReady = false;
Serial.print("Starting Modem ... ");
show_display(firstLine, "Starting Modem...", " ", " ", 0);
displayShow(firstLine, "Starting Modem...", " ", " ", 0);
pinMode(A7670_ResetPin, OUTPUT); //A7670 Reset
digitalWrite(A7670_ResetPin, LOW);
@@ -60,7 +61,7 @@
modemReady = true;
i = 1;
Serial.println("Modem Ready!\n");
show_display(firstLine, "Starting Modem...", "---> Modem Ready", " ", 0);
displayShow(firstLine, "Starting Modem...", "---> Modem Ready", " ", 0);
return true;
}
}
@@ -78,7 +79,7 @@
delay(1000);
//setup_gps(); // if gps active / won't be need for now
} else {
show_display(firstLine, "Starting Modem...", "---> Failed !!!", " ", 0);
displayShow(firstLine, "Starting Modem...", "---> Failed !!!", " ", 0);
Serial.println(F("*********** Failed to connect to the modem! ***********"));
}
}
@@ -98,26 +99,26 @@
//Serial.println(response); // DEBUG of Modem AT message
if(response.indexOf("verified") >= 0) {
Serial.println("Logged! (User Validated)\n");
show_display(firstLine, "Connecting APRS-IS...", "---> Logged!", " ", 1000);
displayShow(firstLine, "Connecting APRS-IS...", "---> Logged!", " ", 1000);
Serial.println("#################### APRS-IS FEED ####################");
validAT = true;
i = 1;
delayATMessage = 0;
} else if (ATMessage == "AT+NETOPEN" && response.indexOf("OK") >= 0) {
Serial.println("Port Open!");
show_display(firstLine, "Opening Port...", "---> Port Open", " ", 0);
displayShow(firstLine, "Opening Port...", "---> Port Open", " ", 0);
validAT = true;
i = 1;
delayATMessage = 0;
} else if (ATMessage == "AT+NETOPEN" && response.indexOf("Network is already opened") >= 0) {
Serial.println("Port Open! (was already opened)");
show_display(firstLine, "Opening Port...", "---> Port Open", " ", 0);
displayShow(firstLine, "Opening Port...", "---> Port Open", " ", 0);
validAT = true;
i = 1;
delayATMessage = 0;
} else if (ATMessage.indexOf("AT+CIPOPEN") == 0 && response.indexOf("PB DONE") >= 0) {
Serial.println("Contacted!");
show_display(firstLine, "Connecting APRS-IS...", "---> Contacted", " ", 0);
displayShow(firstLine, "Connecting APRS-IS...", "---> Contacted", " ", 0);
validAT = true;
i = 1;
delayATMessage = 0;
@@ -155,17 +156,17 @@
Serial.println("-----> Connecting to APRS IS");
while (!modemStartUp) {
Serial.print("Opening Port... ");
show_display(firstLine, "Opening Port...", " ", " ", 0);
displayShow(firstLine, "Opening Port...", " ", " ", 0);
modemStartUp = checkATResponse("AT+NETOPEN");
delay(2000);
} while (!serverStartUp) {
Serial.print("Connecting APRS-IS Server... ");
show_display(firstLine, "Connecting APRS-IS...", " ", " ", 0);
displayShow(firstLine, "Connecting APRS-IS...", " ", " ", 0);
serverStartUp = checkATResponse("AT+CIPOPEN=0,\"TCP\",\"" + String(Config.aprs_is.server) + "\"," + String(Config.aprs_is.port));
delay(2000);
} while (!userBytesSended) {
Serial.print("Writing User Login Data ");
show_display(firstLine, "Connecting APRS-IS...", "---> User Login Data", " ", 0);
displayShow(firstLine, "Connecting APRS-IS...", "---> User Login Data", " ", 0);
userBytesSended = checkATResponse("AT+CIPSEND=0," + String(loginInfo.length()+1));
delay(2000);
} while (!modemLoggedToAPRSIS) {
@@ -200,6 +201,6 @@
}
}
delay(1);
}
}
}
#endif

View File

@@ -1,186 +1,212 @@
/*______________________________________________________________________________________________________________
/*___________________________________________________________________
██╗ ██████╗ ██████╗ █████╗ █████╗ ██████╗ ██████╗ ███████╗ ██╗ ██████╗ █████╗ ████████╗███████╗
██║ ██╔═══██╗██╔══██╗██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗██╔════╝ ██║██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
██║ ██║ ██║██████╔╝███████║ ███████║██████╔╝██████╔╝███████╗ ██║██║ ███╗███████║ ██║ █████╗
██║ ██║ ██║██╔══██╗██╔══██║ ██╔══██║██╔═══╝ ██╔══██╗╚════██║ ██║██║ ██║██╔══██║ ██║ ██╔══╝
███████╗╚██████╔╝██║ ██║██║ ██║ ██║ ██║██║ ██║ ██║███████║ ██║╚██████╔╝██║ ██║ ██║ ███████╗
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
██╗ ██████╗ ██████╗ █████╗ █████╗ ██████╗ ██████╗ ███████╗
██║ ██╔═══██╗██╔══██╗██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗██╔════╝
██║ ██║ ██║██████╔╝███████║ ███████║██████╔╝██████╔╝███████╗
██║ ██║ ██║██╔══██╗██╔══██║ ██╔══██║██╔═══╝ ██╔══██╗╚════██║
███████╗╚██████╔╝██║ ██║██║ ██║ ██║ ██║██║ ██║ ██║███████║
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝
██╗ ██████╗ █████╗ ████████╗███████╗
██║██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
██║██║ ███╗███████║ ██║ █████╗
██║██║ ██║██╔══██║ ██║ ██╔══╝
██║╚██████╔╝██║ ██║ ██║ ███████╗
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
Ricardo Guzman - CA2RXU
https://github.com/richonguzman/LoRa_APRS_Tracker
(donations : http://paypal.me/richonguzman)
______________________________________________________________________________________________________________*/
Ricardo Guzman - CA2RXU
https://github.com/richonguzman/LoRa_APRS_Tracker
(donations : http://paypal.me/richonguzman)
___________________________________________________________________*/
#include <ElegantOTA.h>
#include <TinyGPS++.h>
#include <Arduino.h>
#include <WiFi.h>
#include <vector>
#include "configuration.h"
#include "battery_utils.h"
#include "aprs_is_utils.h"
#include "station_utils.h"
#include "boards_pinout.h"
#include "battery_utils.h"
#include "board_pinout.h"
#include "syslog_utils.h"
#include "query_utils.h"
#include "power_utils.h"
#include "sleep_utils.h"
#include "lora_utils.h"
#include "wifi_utils.h"
#include "digi_utils.h"
#include "gps_utils.h"
#include "bme_utils.h"
#include "web_utils.h"
#include "tnc_utils.h"
#include "ntp_utils.h"
#include "wx_utils.h"
#include "display.h"
#include "utils.h"
#ifdef HAS_A7670
#include "A7670_utils.h"
#endif
String versionDate = "2024.06.21";
Configuration Config;
WiFiClient espClient;
uint8_t myWiFiAPIndex = 0;
int myWiFiAPSize = Config.wifiAPs.size();
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
String versionDate = "2025-04-25";
Configuration Config;
WiFiClient espClient;
#ifdef HAS_GPS
HardwareSerial gpsSerial(1);
TinyGPSPlus gps;
uint32_t gpsSatelliteTime = 0;
bool gpsInfoToggle = false;
#endif
bool isUpdatingOTA = false;
uint32_t lastBatteryCheck = 0;
uint8_t myWiFiAPIndex = 0;
int myWiFiAPSize = Config.wifiAPs.size();
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
bool backUpDigiMode = false;
bool modemLoggedToAPRSIS = false;
bool isUpdatingOTA = false;
uint32_t lastBatteryCheck = 0;
bool backUpDigiMode = false;
bool modemLoggedToAPRSIS = false;
#ifdef HAS_EPAPER
uint32_t lastEpaperTime = 0;
extern String lastEpaperText;
#endif
std::vector<ReceivedPacket> receivedPackets;
String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine;
//#define STARTUP_DELAY 5 //min
void setup() {
Serial.begin(115200);
POWER_Utils::setup();
Utils::setupDisplay();
Config.check();
LoRa_Utils::setup();
Utils::validateFreqs();
GPS_Utils::generateBeacons();
GPS_Utils::setup();
STATION_Utils::loadBlacklistAndManagers();
#ifdef STARTUP_DELAY // (TEST) just to wait for WiFi init of Routers
show_display("", " STARTUP DELAY ...", "", "", 0);
delay(STARTUP_DELAY * 60 * 1000);
displayShow("", " STARTUP DELAY ...", "", "", 0);
delay(STARTUP_DELAY * 60 * 1000);
#endif
#ifdef HELTEC_HTCT62
if (Config.lowPowerMode) {
gpio_wakeup_enable(GPIO_NUM_3, GPIO_INTR_HIGH_LEVEL);
esp_deep_sleep_enable_gpio_wakeup(GPIO_NUM_3, ESP_GPIO_WAKEUP_GPIO_HIGH);
long lastBeacon = 0;
LoRa_Utils::startReceive();
while (true) {
auto wakeup_reason = esp_sleep_get_wakeup_cause();
if (wakeup_reason == 7) { // packet received
Serial.println("Received packet");
String packet = LoRa_Utils::receivePacket();
Serial.println(packet);
if (Config.digi.mode == 2) DIGI_Utils::processLoRaPacket(packet);
if (packet.indexOf(Config.callsign + ":?APRSELP{") != -1) { // Send `?APRSELP` to exit low power
Serial.println("Got ?APRSELP message, exiting from low power mode");
break;
};
}
long time = esp_timer_get_time() / 1000000;
if (lastBeacon == 0 || time - lastBeacon >= Config.beacon.interval * 60) {
Serial.println("Sending beacon");
String comment = Config.beacon.comment;
if (Config.battery.sendInternalVoltage) comment += " Batt=" + String(BATTERY_Utils::checkInternalVoltage(),2) + "V";
if (Config.battery.sendExternalVoltage) comment += " Ext=" + String(BATTERY_Utils::checkExternalVoltage(),2) + "V";
STATION_Utils::addToOutputPacketBuffer(GPS_Utils::getiGateLoRaBeaconPacket() + comment);
lastBeacon = time;
}
LoRa_Utils::startReceive();
Serial.println("Sleeping");
long sleep = (Config.beacon.interval * 60) - (time - lastBeacon);
Serial.flush();
esp_sleep_enable_timer_wakeup(sleep * 1000000);
esp_light_sleep_start();
Serial.println("Waked up");
}
Config.loramodule.rxActive = false;
}
#endif
SLEEP_Utils::setup();
WIFI_Utils::setup();
NTP_Utils::setup();
SYSLOG_Utils::setup();
BME_Utils::setup();
WX_Utils::setup();
WEB_Utils::setup();
TNC_Utils::setup();
#ifdef HAS_A7670
A7670_Utils::setup();
#endif
Utils::checkRebootMode();
APRS_IS_Utils::firstConnection();
}
void loop() {
WIFI_Utils::checkIfAutoAPShouldPowerOff();
if (Config.digi.ecoMode == 1) {
SLEEP_Utils::checkWakeUpFlag();
Utils::checkBeaconInterval();
STATION_Utils::processOutputPacketBufferUltraEcoMode();
Utils::checkSleepByLowBatteryVoltage(1);
SLEEP_Utils::startSleeping();
} else {
WIFI_Utils::checkAutoAPTimeout();
if (isUpdatingOTA) {
ElegantOTA.loop();
return; // Don't process IGate and Digi during OTA update
}
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) {
gpsInfoToggle = !gpsInfoToggle;
gpsSatelliteTime = millis();
}
if (gpsInfoToggle) {
thirdLine = "Satellite(s): ";
String gpsData = String(gps.satellites.value());
if (gpsData.length() < 2) gpsData = "0" + gpsData; // Ensure two-digit formatting
thirdLine += gpsData;
} else {
thirdLine = Utils::getLocalIP();
}
} else {
thirdLine = Utils::getLocalIP();
}
#else
thirdLine = Utils::getLocalIP();
#endif
if (Config.lowVoltageCutOff > 0) {
BATTERY_Utils::checkIfShouldSleep();
}
#ifdef HAS_A7670
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
#else
WIFI_Utils::checkWiFi();
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) APRS_IS_Utils::connect();
#endif
thirdLine = Utils::getLocalIP();
NTP_Utils::update();
TNC_Utils::loop();
WIFI_Utils::checkWiFi(); // Always use WiFi, not related to IGate/Digi mode
Utils::checkDisplayInterval();
Utils::checkBeaconInterval();
APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func?
#ifdef HAS_A7670
if (Config.aprs_is.active && !modemLoggedToAPRSIS) A7670_Utils::APRS_IS_connect();
#else
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) APRS_IS_Utils::connect();
#endif
TNC_Utils::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 = "";
if (Config.loramodule.rxActive) {
packet = LoRa_Utils::receivePacket(); // We need to fetch LoRa packet above APRSIS and Digi
}
if (packet != "") {
if (Config.aprs_is.active) { // If APRSIS enabled
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
String packet = "";
if (Config.loramodule.rxActive) {
packet = LoRa_Utils::receivePacket(); // We need to fetch LoRa packet above APRSIS and Digi
}
if (Config.digi.mode == 2 || backUpDigiMode) { // If Digi enabled
STATION_Utils::clean25SegBuffer();
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
if (packet != "") {
if (Config.aprs_is.active) { // If APRSIS enabled
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();
DIGI_Utils::processLoRaPacket(packet); // Send received packet to Digi
}
if (Config.tnc.enableServer) { // If TNC server enabled
TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
}
if (Config.tnc.enableSerial) { // If Serial KISS enabled
TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
}
}
if (Config.tnc.enableServer) { // If TNC server enabled
TNC_Utils::sendToClients(packet); // Send received packet to TNC KISS
}
if (Config.tnc.enableSerial) { // If Serial KISS enabled
TNC_Utils::sendToSerial(packet); // Send received packet to Serial KISS
if (Config.aprs_is.active) {
APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
}
STATION_Utils::processOutputPacketBuffer();
#ifdef HAS_EPAPER // Only consider updating every 10 seconds (when data to show is different from before)
if(lastEpaperTime == 0 || millis() - lastEpaperTime > 10000) {
String posibleEpaperText = firstLine + secondLine + thirdLine + fourthLine + fifthLine + sixthLine + seventhLine;
if (lastEpaperText != posibleEpaperText) {
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
lastEpaperText = posibleEpaperText;
lastEpaperTime = millis();
}
}
#else
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
#endif
Utils::checkRebootTime();
Utils::checkSleepByLowBatteryVoltage(1);
}
}
if (Config.aprs_is.active) { // If APRSIS enabled
APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
}
STATION_Utils::processOutputPacketBuffer();
// ESP32 (and ESPS3) work?
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
Utils::checkRebootTime();
Utils::checkSleepByLowBatteryVoltage(1);
}
// ESP32C3 :
// - HT-CT62 sleeps??
// - and others?

View File

@@ -2,6 +2,7 @@
#include "configuration.h"
#include "aprs_is_utils.h"
#include "station_utils.h"
#include "board_pinout.h"
#include "syslog_utils.h"
#include "query_utils.h"
#include "A7670_utils.h"
@@ -9,6 +10,7 @@
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern WiFiClient espClient;
extern uint32_t lastScreenOn;
@@ -22,7 +24,8 @@ extern String seventhLine;
extern bool modemLoggedToAPRSIS;
extern bool backUpDigiMode;
uint32_t lastRxTime = millis();
uint32_t lastRxTime = millis();
bool passcodeValid = false;
#ifdef HAS_A7670
extern bool stationBeacon;
@@ -50,19 +53,16 @@ namespace APRS_IS_Utils {
}
if (count == 20) {
Serial.println("Tried: " + String(count) + " FAILED!");
}
else {
} else {
Serial.println("Connected!\n(Server: " + String(Config.aprs_is.server) + " / Port: " + String(Config.aprs_is.port) + ")");
// String filter = "t/m/" + Config.callsign + "/" + (String)Config.aprs_is.reportingDistance;
String aprsauth = "user ";
aprsauth += Config.callsign;
aprsauth += " pass ";
aprsauth += Config.aprs_is.passcode;
aprsauth += " vers CA2RXU_LoRa_iGate 1.3 filter ";
aprsauth += Config.aprs_is.filter;
upload(aprsauth);
delay(200);
String aprsAuth = "user ";
aprsAuth += Config.callsign;
aprsAuth += " pass ";
aprsAuth += Config.aprs_is.passcode;
aprsAuth += " vers CA2RXU_iGate 2.3 filter ";
aprsAuth += Config.aprs_is.filter;
upload(aprsAuth);
}
}
@@ -71,13 +71,13 @@ namespace APRS_IS_Utils {
if (WiFi.status() == WL_CONNECTED) {
wifiState = "OK";
} else {
if (backUpDigiMode) {
if (backUpDigiMode || Config.digi.ecoMode == 1 || Config.digi.ecoMode == 2) {
wifiState = "--";
} else {
wifiState = "AP";
}
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
display_toggle(true);
displayToggle(true);
}
lastScreenOn = millis();
}
@@ -99,9 +99,9 @@ namespace APRS_IS_Utils {
}
#endif
if(aprsisState == "--" && !Config.display.alwaysOn && Config.display.timeout != 0) {
display_toggle(true);
displayToggle(true);
lastScreenOn = millis();
}
}
}
secondLine = "WiFi: ";
secondLine += wifiState;
@@ -129,6 +129,88 @@ namespace APRS_IS_Utils {
return buildedPacket;
}
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty) {
String receivedMessage;
if (packet.indexOf("{") > 0) { // ack?
String ackMessage = "ack";
ackMessage.concat(packet.substring(packet.indexOf("{") + 1));
ackMessage.trim();
//Serial.println(ackMessage);
String addToBuffer = Config.callsign;
addToBuffer += ">APLRG1";
if (!thirdParty) addToBuffer += ",RFONLY";
if (Config.beacon.path != "") {
addToBuffer += ",";
addToBuffer += Config.beacon.path;
}
addToBuffer += "::";
String processedSender = sender;
for (int i = sender.length(); i < 9; i++) {
processedSender += ' ';
}
addToBuffer += processedSender;
addToBuffer += ":";
addToBuffer += ackMessage;
STATION_Utils::addToOutputPacketBuffer(addToBuffer);
receivedMessage = packet.substring(packet.indexOf(":") + 1, packet.indexOf("{"));
} else {
receivedMessage = packet.substring(packet.indexOf(":") + 1);
}
if (receivedMessage.indexOf("?") == 0) {
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
displayToggle(true);
}
STATION_Utils::addToOutputPacketBuffer(QUERY_Utils::process(receivedMessage, sender, false, thirdParty));
lastScreenOn = millis();
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, "Callsign = " + sender, "TYPE --> QUERY", 0);
return true;
}
else {
return false;
}
}
void processLoRaPacket(const String& packet) {
if (passcodeValid && (espClient.connected() || modemLoggedToAPRSIS)) {
if (packet.indexOf("NOGATE") == -1 && packet.indexOf("RFONLY") == -1) {
int firstColonIndex = packet.indexOf(":");
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] != '}' && packet.indexOf("TCPIP") == -1) {
const String& Sender = packet.substring(3, packet.indexOf(">"));
if (Sender != Config.callsign && Utils::checkValidCallsign(Sender)) {
STATION_Utils::updateLastHeard(Sender);
Utils::typeOfPacket(packet.substring(3), 0); // LoRa-APRS
const String& AddresseeAndMessage = packet.substring(packet.indexOf("::") + 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!
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);
}
}
}
}
}
}
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType) {
String packet = aprsisPacket;
packet.trim();
@@ -174,94 +256,23 @@ namespace APRS_IS_Utils {
return outputPacket;
}
bool processReceivedLoRaMessage(const String& sender, const String& packet) {
String receivedMessage;
if (packet.indexOf("{") > 0) { // ack?
String ackMessage = "ack";
ackMessage.concat(packet.substring(packet.indexOf("{") + 1));
ackMessage.trim();
//Serial.println(ackMessage);
String addToBuffer = Config.callsign;
addToBuffer += ">APLRG1,RFONLY";
if (Config.beacon.path != "") {
addToBuffer += ",";
addToBuffer += Config.beacon.path;
}
addToBuffer += "::";
String processedSender = sender;
for (int i = sender.length(); i < 9; i++) {
processedSender += ' ';
}
addToBuffer += processedSender;
addToBuffer += ":";
addToBuffer += ackMessage;
STATION_Utils::addToOutputPacketBuffer(addToBuffer);
receivedMessage = packet.substring(packet.indexOf(":") + 1, packet.indexOf("{"));
} else {
receivedMessage = packet.substring(packet.indexOf(":") + 1);
}
if (receivedMessage.indexOf("?") == 0) {
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
display_toggle(true);
}
STATION_Utils::addToOutputPacketBuffer(QUERY_Utils::process(receivedMessage, sender, 0)); // LoRa
lastScreenOn = millis();
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, "Callsign = " + sender, "TYPE --> QUERY", 0);
return true;
}
else {
return false;
}
}
void processLoRaPacket(const String& packet) {
if (espClient.connected() || modemLoggedToAPRSIS) {
if (packet != "") {
if ((packet.substring(0, 3) == "\x3c\xff\x01") && (packet.indexOf("}") == -1 && packet.indexOf("TCPIP") == -1) && (packet.indexOf("NOGATE") == -1) && (packet.indexOf("RFONLY") == -1)) {
const String& Sender = packet.substring(3, packet.indexOf(">"));
if (Sender != Config.callsign && Utils::checkValidCallsign(Sender)) {
STATION_Utils::updateLastHeard(Sender);
Utils::typeOfPacket(packet.substring(3), 0); // LoRa-APRS
const String& AddresseeAndMessage = packet.substring(packet.indexOf("::") + 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!
queryMessage = processReceivedLoRaMessage(Sender, checkForStartingBytes(AddresseeAndMessage));
}
if (!queryMessage) {
const String& aprsPacket = buildPacketToUpload(packet);
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
display_toggle(true);
}
lastScreenOn = millis();
#ifdef HAS_A7670
stationBeacon = true;
A7670_Utils::uploadToAPRSIS(aprsPacket);
stationBeacon = false;
#else
upload(aprsPacket);
#endif
Utils::println("---> Uploaded to APRS-IS");
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
}
}
}
}
}
}
void processAPRSISPacket(const String& packet) {
if (!packet.startsWith("#")) {
if (!passcodeValid && packet.indexOf(Config.callsign) != -1) {
if (packet.indexOf("unverified") != -1 ) {
Serial.println("\n****APRS PASSCODE NOT VALID****\n");
displayShow(firstLine, "", " APRS PASSCODE", " NOT VALID !!!", "", "", "", 0);
while (1) {};
} else if (packet.indexOf("verified") != -1 ) {
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!
if (Addressee == Config.callsign) { // its for me!
String receivedMessage;
if (AddresseeAndMessage.indexOf("{") > 0) { // ack?
String ackMessage = "ack";
@@ -281,17 +292,18 @@ namespace APRS_IS_Utils {
A7670_Utils::uploadToAPRSIS(ackPacket);
#else
upload(ackPacket);
#endif
#endif
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1, AddresseeAndMessage.indexOf("{"));
} else {
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1);
}
if (receivedMessage.indexOf("?") == 0) {
Utils::println("Received Query APRS-IS : " + packet);
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, 1); // APRSIS
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) {
display_toggle(true);
displayToggle(true);
}
lastScreenOn = millis();
delay(500);
@@ -299,7 +311,7 @@ namespace APRS_IS_Utils {
A7670_Utils::uploadToAPRSIS(queryAnswer);
#else
upload(queryAnswer);
#endif
#endif
SYSLOG_Utils::log(2, queryAnswer, 0, 0.0, 0); // APRSIS TX
fifthLine = "APRS-IS ----> APRS-IS";
sixthLine = Config.callsign;
@@ -311,22 +323,28 @@ namespace APRS_IS_Utils {
seventhLine = "QUERY = ";
seventhLine += receivedMessage;
}
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
} else {
Utils::print("Received Message from APRS-IS : " + packet);
if (STATION_Utils::wasHeard(Addressee)) {
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));
display_toggle(true);
displayToggle(true);
lastScreenOn = millis();
Utils::typeOfPacket(packet, 1); // APRS-LoRa
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
}
}
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
} else if (Config.aprs_is.objectsToRF && packet.indexOf(":;") > 0) {
Utils::println("Received Object from APRS-IS : " + packet);
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 5));
display_toggle(true);
lastScreenOn = millis();
Utils::typeOfPacket(packet, 1); // APRS-LoRa
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");
}
}
}
}
@@ -338,7 +356,7 @@ namespace APRS_IS_Utils {
if (espClient.connected()) {
if (espClient.available()) {
String aprsisPacket = espClient.readStringUntil('\r');
// Serial.println(aprsisPacket);
aprsisPacket.trim(); // Serial.println(aprsisPacket);
processAPRSISPacket(aprsisPacket);
lastRxTime = millis();
}
@@ -346,4 +364,13 @@ namespace APRS_IS_Utils {
#endif
}
void firstConnection() {
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) {
connect();
while (!passcodeValid) {
listenAPRSIS();
}
}
}
}

View File

@@ -1,23 +1,48 @@
#include <Arduino.h>
#include "battery_utils.h"
#include "configuration.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "power_utils.h"
#include "utils.h"
extern Configuration Config;
extern uint32_t lastBatteryCheck;
bool shouldSleepLowVoltage = false;
extern Configuration Config;
extern uint32_t lastBatteryCheck;
float adcReadingTransformation = (3.3/4095);
float voltageDividerCorrection = 0.288;
bool shouldSleepLowVoltage = false;
// for External Voltage Measurment (MAX = 15Volts !!!)
float R1 = 100.000; //in Kilo-Ohms
float R2 = 27.000; //in Kilo-Ohms
float readingCorrection = 0.125;
float multiplyCorrection = 0.035;
float adcReadingTransformation = (3.3/4095);
float voltageDividerCorrection = 0.288;
float readingCorrection = 0.125;
float multiplyCorrection = 0.035;
float voltageDividerTransformation = 0.0;
int telemetryCounter = random(1,999);
#ifdef HAS_ADC_CALIBRATION
#include <esp_adc_cal.h>
#if defined(TTGO_LORA32_V2_1) || defined(TTGO_LORA32_V2_1_915)
#define InternalBattery_ADC_Channel ADC1_CHANNEL_7 // t_lora32 pin35
#define ExternalVoltage_ADC_Channel ADC1_CHANNEL_6 // t_lora32 pin34
#endif
#if CONFIG_IDF_TARGET_ESP32
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_VREF
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32C3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP
#elif CONFIG_IDF_TARGET_ESP32S3
#define ADC_EXAMPLE_CALI_SCHEME ESP_ADC_CAL_VAL_EFUSE_TP_FIT
#endif
esp_adc_cal_characteristics_t adc_chars;
#endif
bool calibrationEnable = false;
namespace BATTERY_Utils {
@@ -26,6 +51,46 @@ namespace BATTERY_Utils {
return (voltage - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void adcCalibration() {
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable) {
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(InternalBattery_ADC_Channel, ADC_ATTEN_DB_12);
adc1_config_channel_atten(ExternalVoltage_ADC_Channel, ADC_ATTEN_DB_12);
}
#endif
}
void adcCalibrationCheck() {
#ifdef HAS_ADC_CALIBRATION
esp_err_t ret;
ret = esp_adc_cal_check_efuse(ADC_EXAMPLE_CALI_SCHEME);
/*if (ret == ESP_ERR_NOT_SUPPORTED) {
Serial.println("Calibration scheme not supported, skip software calibration");
} else if (ret == ESP_ERR_INVALID_VERSION) {
Serial.println("eFuse not burnt, skip software calibration");
} else */
if (ret == ESP_OK) {
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_12, ADC_WIDTH_BIT_12, 1100, &adc_chars);
//Serial.printf("eFuse Vref:%u mV\n", adc_chars.vref);
calibrationEnable = true;
} /*else {
Serial.println("Invalid Calibration Arg");
}*/
#endif
}
void setup() {
if ((Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) && Config.battery.voltageDividerR2 != 0) voltageDividerTransformation = (Config.battery.voltageDividerR1 + Config.battery.voltageDividerR2) / Config.battery.voltageDividerR2;
#if defined(HAS_ADC_CALIBRATION)
if (Config.battery.sendInternalVoltage || Config.battery.monitorInternalVoltage || Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) {
adcCalibrationCheck();
adcCalibration();
}
#endif
}
float checkInternalVoltage() {
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
if(POWER_Utils::isBatteryConnected()) {
@@ -37,38 +102,64 @@ namespace BATTERY_Utils {
int sample;
int sampleSum = 0;
#ifdef ADC_CTRL
#if defined(HELTEC_WIRELESS_TRACKER)
#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)
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
digitalWrite(ADC_CTRL, LOW);
#endif
#endif
for (int i = 0; i < 100; i++) {
#ifdef BATTERY_PIN
sample = analogRead(BATTERY_PIN);
#endif
#if defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
#if defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915)
sample = 0;
#else
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
sample = adc1_get_raw(InternalBattery_ADC_Channel);
} else {
sample = analogRead(BATTERY_PIN);
}
#else
#ifdef BATTERY_PIN
sample = analogRead(BATTERY_PIN);
#else
sample = 0;
#endif
#endif
#endif
sampleSum += sample;
delayMicroseconds(50);
}
#ifdef ADC_CTRL
#if defined(HELTEC_WIRELESS_TRACKER)
#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)
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
digitalWrite(ADC_CTRL, HIGH);
#endif
#ifdef HELTEC_WP
double inputDivider = (1.0 / (10.0 + 10.0)) * 10.0; // The voltage divider is a 10k + 10k resistor in series
#else
double inputDivider = (1.0 / (390.0 + 100.0)) * 100.0; // The voltage divider is a 390k + 100k resistor in series, 100k on the low side.
#endif
return (((sampleSum/100) * adcReadingTransformation) / inputDivider) + 0.285; // Yes, this offset is excessive, but the ADC on the ESP32s3 is quite inaccurate and noisy. Adjust to own measurements.
#else
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
float voltage = esp_adc_cal_raw_to_voltage(sampleSum / 100, &adc_chars);
voltage *= 2; // for 100K/100K voltage divider
voltage /= 1000;
return voltage;
} else {
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
}
#else
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection; // raw voltage without mapping
#endif
#endif
// return mapVoltage(voltage, 3.34, 4.71, 3.0, 4.2); // mapped voltage
#endif
}
@@ -77,39 +168,91 @@ namespace BATTERY_Utils {
int sample;
int sampleSum = 0;
for (int i = 0; i < 100; i++) {
sample = analogRead(Config.battery.externalVoltagePin);
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
sample = adc1_get_raw(ExternalVoltage_ADC_Channel);
} else {
sample = analogRead(Config.battery.externalVoltagePin);
}
#else
sample = analogRead(Config.battery.externalVoltagePin);
#endif
sampleSum += sample;
delayMicroseconds(50);
delayMicroseconds(50);
}
float voltage = ((((sampleSum/100)* adcReadingTransformation) + readingCorrection) * ((R1+R2)/R2)) - multiplyCorrection;
float extVoltage;
#ifdef HAS_ADC_CALIBRATION
if (calibrationEnable){
extVoltage = esp_adc_cal_raw_to_voltage(sampleSum / 100, &adc_chars) * voltageDividerTransformation; // in mV
extVoltage /= 1000;
} else {
extVoltage = ((((sampleSum/100)* adcReadingTransformation) + readingCorrection) * voltageDividerTransformation) - multiplyCorrection;
}
#else
extVoltage = ((((sampleSum/100)* adcReadingTransformation) + readingCorrection) * voltageDividerTransformation) - multiplyCorrection;
#endif
return voltage; // raw voltage without mapping
return extVoltage; // raw voltage without mapping
// return mapVoltage(voltage, 5.05, 6.32, 4.5, 5.5); // mapped voltage
}
void checkIfShouldSleep() {
if (lastBatteryCheck == 0 || millis() - lastBatteryCheck >= 15 * 60 * 1000) {
lastBatteryCheck = millis();
if (checkInternalVoltage() < Config.lowVoltageCutOff) {
ESP.deepSleep(1800000000); // 30 min sleep (60s = 60e6)
}
}
}
void startupBatteryHealth() {
#ifdef BATTERY_PIN
if (Config.battery.monitorInternalVoltage && checkInternalVoltage() < Config.battery.internalSleepVoltage + 0.1) {
shouldSleepLowVoltage = true;
}
#endif
if (Config.battery.monitorExternalVoltage && checkExternalVoltage() < Config.battery.externalSleepVoltage + 0.1) {
shouldSleepLowVoltage = true;
}
#ifndef HELTEC_WP
if (Config.battery.monitorExternalVoltage && checkExternalVoltage() < Config.battery.externalSleepVoltage + 0.1) {
shouldSleepLowVoltage = true;
}
#endif
if (shouldSleepLowVoltage) {
Utils::checkSleepByLowBatteryVoltage(0);
}
}
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType) { // 0 = internal battery(0-4,2V) , 1 = external battery(0-15V)
String encodedBytes;
int tempValue;
if (firstBytes) {
tempValue = value;
} else {
switch (voltageType) {
case 0:
tempValue = value * 100; // Internal voltage calculation
break;
case 1:
tempValue = (value * 100) / 2; // External voltage calculation
break;
default:
tempValue = value;
break;
}
}
int firstByte = tempValue / 91;
tempValue -= firstByte * 91;
encodedBytes = char(firstByte + 33);
encodedBytes += char(tempValue + 33);
return encodedBytes;
}
String generateEncodedTelemetry() {
String telemetry = "|";
telemetry += generateEncodedTelemetryBytes(telemetryCounter, true, 0);
telemetryCounter++;
if (telemetryCounter == 1000) {
telemetryCounter = 0;
}
if (Config.battery.sendInternalVoltage) telemetry += generateEncodedTelemetryBytes(checkInternalVoltage(), false, 0);
if (Config.battery.sendExternalVoltage) telemetry += generateEncodedTelemetryBytes(checkExternalVoltage(), false, 1);
telemetry += "|";
return telemetry;
}
}

View File

@@ -1,16 +0,0 @@
#ifndef BATTERY_UTILS_H_
#define BATTERY_UTILS_H_
#include <Arduino.h>
namespace BATTERY_Utils {
float checkInternalVoltage();
float checkExternalVoltage();
void checkIfShouldSleep(); // ????
void startupBatteryHealth();
}
#endif

View File

@@ -1,23 +0,0 @@
#ifndef BME_UTILS_H_
#define BME_UTILS_H_
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_BME680.h>
#include "Adafruit_Si7021.h"
#include <Arduino.h>
namespace BME_Utils {
void getWxModuleAddres();
void setup();
String generateTempString(const float bmeTemp);
String generateHumString(const float bmeHum);
String generatePresString(const float bmePress);
String readDataSensor();
}
#endif

View File

@@ -1,219 +0,0 @@
#ifndef PINS_CONFIG_H_
#define PINS_CONFIG_H_
#include <Arduino.h>
#undef OLED_SDA
#undef OLED_SCL
#undef OLED_RST
// LORA MODULES
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(ESP32_DIY_LoRa) || defined(TTGO_T_Beam_V1_2) || defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_LORA32_V2_1_915) || defined(ESP32_DIY_LoRa_915) || defined(TTGO_T_Beam_V1_2_915) || defined(TTGO_T_Beam_V1_0_915)
#define RADIO_SCLK_PIN 5 // GPIO5 - SX1278 SCK
#define RADIO_MISO_PIN 19 // GPIO19 - SX1278 MISO
#define RADIO_MOSI_PIN 27 // GPIO27 - SX1278 MOSI
#define RADIO_CS_PIN 18 // GPIO18 - SX1278 CS ---> NSS
#define RADIO_RST_PIN 14 // GPIO14 - SX1278 RST
#define RADIO_BUSY_PIN 26 // GPIO26 - SX1278 IRQ ---->DIO0
#endif
#if defined(HELTEC_V3) || defined(HELTEC_WSL_V3) || defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_WS)
#define RADIO_SCLK_PIN 9 // SX1262 SCK
#define RADIO_MISO_PIN 11 // SX1262 MISO
#define RADIO_MOSI_PIN 10 // SX1262 MOSI
#define RADIO_CS_PIN 8 // SX1262 NSS
#define RADIO_RST_PIN 12 // SX1262 RST
#define RADIO_DIO1_PIN 14 // SX1262 DIO1
#define RADIO_BUSY_PIN 13 // SX1262 BUSY
#endif
#if defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915) // Ebyte E22 400M30S (SX1268) or E22 900M30S (SX1262)
#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
#endif
#ifdef WEMOS_LOLIN32_OLED_DIY_LoRa
#define RADIO_SCLK_PIN 15
#define RADIO_MISO_PIN 13
#define RADIO_MOSI_PIN 12
#define RADIO_CS_PIN 14
#define RADIO_RST_PIN 2
#define RADIO_BUSY_PIN 25
#endif
#if defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2_SX1262)
#define RADIO_SCLK_PIN 5
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 27
#define RADIO_CS_PIN 18
#define RADIO_DIO0_PIN 26
#define RADIO_RST_PIN 23
#define RADIO_DIO1_PIN 33
#define RADIO_BUSY_PIN 32
#endif
#if defined(OE5HWN_MeshCom)
#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 33
#define RADIO_BUSY_PIN 26
#define RADIO_RXEN 14
#define RADIO_TXEN 13
#endif
#ifdef HELTEC_HTCT62
#define RADIO_SCLK_PIN 10 // SX1262 SCK
#define RADIO_MISO_PIN 6 // SX1262 MISO
#define RADIO_MOSI_PIN 7 // SX1262 MOSI
#define RADIO_CS_PIN 8 // SX1262 NSS
#define RADIO_RST_PIN 5 // SX1262 RST
#define RADIO_DIO1_PIN 3 // SX1262 DIO1
#define RADIO_BUSY_PIN 4 // SX1262 BUSY
#endif
#if defined(ESP32_DIY_LoRa_A7670) || defined(ESP32_DIY_LoRa_A7670_915)
#define RADIO_SCLK_PIN 18
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 23
#define RADIO_CS_PIN 2
#define RADIO_RST_PIN 0
#define RADIO_BUSY_PIN 32
#define A7670_PWR_PIN 4
#define A7670_ResetPin 5
#define A7670_TX_PIN 26
#define A7670_RX_PIN 27
#endif
#ifdef WEMOS_D1_R32_RA02
#define RADIO_SCLK_PIN 18
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 23
#define RADIO_CS_PIN 5
#define RADIO_BUSY_PIN 12
#define RADIO_RST_PIN 13
#define RADIO_DIO1_PIN 14
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST 36
#endif
#if defined(ESP32C3_DIY_1W_LoRa) || defined(ESP32C3_DIY_1W_LoRa_915)
#define RADIO_SCLK_PIN 8
#define RADIO_MISO_PIN 9
#define RADIO_MOSI_PIN 10
#define RADIO_CS_PIN 5
#define RADIO_RST_PIN 4
#define RADIO_DIO1_PIN 2
#define RADIO_BUSY_PIN 3
#define RADIO_RXEN 6
#define RADIO_TXEN 7
#endif
// OLED
#if defined(TTGO_T_LORA32_V2_1) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa) || defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_2) || defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2_SX1262) || defined(OE5HWN_MeshCom) || defined(ESP32_DIY_LoRa_A7670) || defined(TTGO_T_LORA32_V2_1_915) || defined(ESP32_DIY_LoRa_915) || defined(TTGO_T_Beam_V1_0_915) || defined(TTGO_T_Beam_V1_2_915) || defined(ESP32_DIY_LoRa_A7670_915) || defined(ESP32_DIY_1W_LoRa_915)
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#endif
#ifdef HELTEC_V2
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
#endif
#if defined(HELTEC_V3) || defined(HELTEC_WS)
#define OLED_SDA 17
#define OLED_SCL 18
#define OLED_RST 21
#endif
#ifdef WEMOS_LOLIN32_OLED_DIY_LoRa
#define OLED_SDA 5
#define OLED_SCL 4
#define OLED_RST -1
#endif
#if !defined(HELTEC_HTCT62) && !defined(HELTEC_WSL_V3) && !defined(ESP32C3_DIY_1W_LoRa) && !defined(ESP32C3_DIY_1W_LoRa_915)
#define HAS_DISPLAY
#endif
// Leds and other stuff
#ifdef HELTEC_HTCT62
#define BATTERY_PIN 1
#endif
#if defined(TTGO_T_LORA32_V2_1) || defined(TTGO_T_LORA32_V2_1_915)
#define INTERNAL_LED_PIN 25 // Green Led
#define BATTERY_PIN 35
#endif
#if defined(HELTEC_V2)
#define INTERNAL_LED_PIN 25
#define BATTERY_PIN 37
#define ADC_CTRL 21
#endif
#if defined(HELTEC_V3) || defined(HELTEC_WSL_V3) || defined(HELTEC_WS)
#define INTERNAL_LED_PIN 35
#define BATTERY_PIN 1
#define VEXT_CTRL 36
#define ADC_CTRL 37 // Heltec WSL_V3 just like Heltec WT
#define BOARD_I2C_SDA 41
#define BOARD_I2C_SCL 42
#endif
#if defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_LoRa_915) || defined(ESP32_DIY_1W_LoRa) || defined(ESP32_DIY_1W_LoRa_915)
#define INTERNAL_LED_PIN 2
#endif
#if defined(ESP32_DIY_LoRa_A7670) || defined(ESP32_DIY_LoRa_A7670_915)
#define INTERNAL_LED_PIN 13 // 13 for V1.1 and 12 for V1.0
#define BATTERY_PIN 35
#endif
#ifdef HELTEC_WIRELESS_TRACKER
#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 BOARD_I2C_SDA 7
#define BOARD_I2C_SCL 6
#endif
#ifdef ESP32_C3_DIY_LoRa // just testing!
#define OLED_SDA 8
#define OLED_SCL 9
#define OLED_RST 10
#define RADIO_SCLK_PIN 4
#define RADIO_MISO_PIN 5
#define RADIO_MOSI_PIN 6
#define RADIO_CS 7
#define RADIO_RST_PIN 3
#define RADIO_IRQ_PIN 2
#endif
/* (Same pins for LILYGO LoRa32 and ESP32 Wroom Dev )
SX1278-------------------> ESP32 ttgo-lora32-v21 and ESP32 WROOM Dev
GND GND
DIO1 -
DIO2 -
DIO3 -
VCC 3.3V
MISO 19
MOSI 27
SCLK 5
NSS 18
DIO0 26
REST 14
GND - */
#endif

View File

@@ -4,18 +4,11 @@
#include "display.h"
void Configuration::check() {
if (reload) {
show_display("------- UPDATE ------", "config is old", "device will update", "and then reboot", 1000);
writeFile();
bool shouldSleepStop = true;
ESP.restart();
}
}
void Configuration::writeFile() {
Serial.println("Saving config..");
Serial.println("Saving config...");
StaticJsonDocument<2560> data;
File configFile = SPIFFS.open("/igate_conf.json", "w");
@@ -27,43 +20,47 @@ void Configuration::writeFile() {
}
}
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
data["wifi"]["autoAP"]["powerOff"] = wifiAutoAP.powerOff;
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
data["callsign"] = callsign;
data["callsign"] = callsign;
data["aprs_is"]["active"] = aprs_is.active;
data["aprs_is"]["passcode"] = aprs_is.passcode;
data["aprs_is"]["server"] = aprs_is.server;
data["aprs_is"]["port"] = aprs_is.port;
data["aprs_is"]["filter"] = aprs_is.filter;
data["aprs_is"]["messagesToRF"] = aprs_is.messagesToRF;
data["aprs_is"]["objectsToRF"] = aprs_is.objectsToRF;
data["aprs_is"]["active"] = aprs_is.active;
data["aprs_is"]["passcode"] = aprs_is.passcode;
data["aprs_is"]["server"] = aprs_is.server;
data["aprs_is"]["port"] = aprs_is.port;
data["aprs_is"]["filter"] = aprs_is.filter;
data["aprs_is"]["messagesToRF"] = aprs_is.messagesToRF;
data["aprs_is"]["objectsToRF"] = aprs_is.objectsToRF;
data["beacon"]["comment"] = beacon.comment;
data["beacon"]["interval"] = beacon.interval;
data["beacon"]["latitude"] = beacon.latitude;
data["beacon"]["longitude"] = beacon.longitude;
data["beacon"]["overlay"] = beacon.overlay;
data["beacon"]["symbol"] = beacon.symbol;
data["beacon"]["sendViaAPRSIS"] = beacon.sendViaAPRSIS;
data["beacon"]["sendViaRF"] = beacon.sendViaRF;
data["beacon"]["path"] = beacon.path;
data["beacon"]["comment"] = beacon.comment;
data["beacon"]["interval"] = beacon.interval;
data["beacon"]["latitude"] = beacon.latitude;
data["beacon"]["longitude"] = beacon.longitude;
data["beacon"]["overlay"] = beacon.overlay;
data["beacon"]["symbol"] = beacon.symbol;
data["beacon"]["sendViaAPRSIS"] = beacon.sendViaAPRSIS;
data["beacon"]["sendViaRF"] = beacon.sendViaRF;
data["beacon"]["path"] = beacon.path;
data["digi"]["mode"] = digi.mode;
data["beacon"]["gpsActive"] = beacon.gpsActive;
data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity;
data["lora"]["rxFreq"] = loramodule.rxFreq;
data["lora"]["txFreq"] = loramodule.txFreq;
data["lora"]["spreadingFactor"] = loramodule.spreadingFactor;
data["lora"]["signalBandwidth"] = loramodule.signalBandwidth;
data["lora"]["codingRate4"] = loramodule.codingRate4;
data["lora"]["power"] = loramodule.power;
data["lora"]["txActive"] = loramodule.txActive;
data["lora"]["rxActive"] = loramodule.rxActive;
data["digi"]["mode"] = digi.mode;
data["digi"]["ecoMode"] = digi.ecoMode;
data["display"]["alwaysOn"] = display.alwaysOn;
data["display"]["timeout"] = display.timeout;
data["display"]["turn180"] = display.turn180;
data["lora"]["rxFreq"] = loramodule.rxFreq;
data["lora"]["txFreq"] = loramodule.txFreq;
data["lora"]["spreadingFactor"] = loramodule.spreadingFactor;
data["lora"]["signalBandwidth"] = loramodule.signalBandwidth;
data["lora"]["codingRate4"] = loramodule.codingRate4;
data["lora"]["power"] = loramodule.power;
data["lora"]["txActive"] = loramodule.txActive;
data["lora"]["rxActive"] = loramodule.rxActive;
data["display"]["alwaysOn"] = display.alwaysOn;
data["display"]["timeout"] = display.timeout;
data["display"]["turn180"] = display.turn180;
data["battery"]["sendInternalVoltage"] = battery.sendInternalVoltage;
data["battery"]["monitorInternalVoltage"] = battery.monitorInternalVoltage;
@@ -73,37 +70,52 @@ void Configuration::writeFile() {
data["battery"]["externalVoltagePin"] = battery.externalVoltagePin;
data["battery"]["monitorExternalVoltage"] = battery.monitorExternalVoltage;
data["battery"]["externalSleepVoltage"] = battery.externalSleepVoltage;
data["battery"]["voltageDividerR1"] = battery.voltageDividerR1;
data["battery"]["voltageDividerR2"] = battery.voltageDividerR2;
data["bme"]["active"] = bme.active;
data["bme"]["heightCorrection"] = bme.heightCorrection;
data["bme"]["temperatureCorrection"] = bme.temperatureCorrection;
data["battery"]["sendVoltageAsTelemetry"] = battery.sendVoltageAsTelemetry;
data["syslog"]["active"] = syslog.active;
data["syslog"]["server"] = syslog.server;
data["syslog"]["port"] = syslog.port;
data["wxsensor"]["active"] = wxsensor.active;
data["wxsensor"]["heightCorrection"] = wxsensor.heightCorrection;
data["wxsensor"]["temperatureCorrection"] = wxsensor.temperatureCorrection;
data["tnc"]["enableServer"] = tnc.enableServer;
data["tnc"]["enableSerial"] = tnc.enableSerial;
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
data["syslog"]["active"] = syslog.active;
data["syslog"]["server"] = syslog.server;
data["syslog"]["port"] = syslog.port;
data["other"]["rebootMode"] = rebootMode;
data["other"]["rebootModeTime"] = rebootModeTime;
data["tnc"]["enableServer"] = tnc.enableServer;
data["tnc"]["enableSerial"] = tnc.enableSerial;
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
data["ota"]["username"] = ota.username;
data["ota"]["password"] = ota.password;
data["other"]["rebootMode"] = rebootMode;
data["other"]["rebootModeTime"] = rebootModeTime;
data["ota"]["username"] = ota.username;
data["ota"]["password"] = ota.password;
data["other"]["rememberStationTime"] = rememberStationTime;
data["other"]["backupDigiMode"] = backupDigiMode;
data["other"]["backupDigiMode"] = backupDigiMode;
data["other"]["lowPowerMode"] = lowPowerMode;
data["other"]["lowVoltageCutOff"] = lowVoltageCutOff;
data["personalNote"] = personalNote;
data["blacklist"] = blacklist;
data["webadmin"]["active"] = webadmin.active;
data["webadmin"]["username"] = webadmin.username;
data["webadmin"]["password"] = webadmin.password;
data["ntp"]["gmtCorrection"] = ntp.gmtCorrection;
data["remoteManagement"]["managers"] = remoteManagement.managers;
data["remoteManagement"]["rfOnly"] = remoteManagement.rfOnly;
serializeJson(data, configFile);
configFile.close();
Serial.println("Config saved");
delay(200);
}
bool Configuration::readFile() {
@@ -128,129 +140,95 @@ bool Configuration::readFile() {
wifiAPs.push_back(wifiap);
}
wifiAutoAP.password = data["wifi"]["autoAP"]["password"].as<String>();
wifiAutoAP.powerOff = data["wifi"]["autoAP"]["powerOff"].as<int>();
wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890";
wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10;
callsign = data["callsign"].as<String>();
rememberStationTime = data["other"]["rememberStationTime"].as<int>();
callsign = data["callsign"] | "NOCALL-10";
rememberStationTime = data["other"]["rememberStationTime"] | 30;
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"].as<bool>();
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"].as<bool>();
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"].as<float>();
beacon.latitude = data["beacon"]["latitude"] | 0.0;
beacon.longitude = data["beacon"]["longitude"] | 0.0;
beacon.comment = data["beacon"]["comment"] | "LoRa APRS";
beacon.interval = data["beacon"]["interval"] | 15;
beacon.overlay = data["beacon"]["overlay"] | "L";
beacon.symbol = data["beacon"]["symbol"] | "a";
beacon.path = data["beacon"]["path"] | "WIDE1-1";
beacon.sendViaAPRSIS = data["beacon"]["sendViaAPRSIS"] | false;
beacon.sendViaRF = data["beacon"]["sendViaRF"] | false;
battery.sendExternalVoltage = data["battery"]["sendExternalVoltage"].as<bool>();
battery.externalVoltagePin = data["battery"]["externalVoltagePin"].as<int>();
battery.monitorExternalVoltage = data["battery"]["monitorExternalVoltage"].as<bool>();
battery.externalSleepVoltage = data["battery"]["externalSleepVoltage"].as<float>();
beacon.gpsActive = data["beacon"]["gpsActive"] | false;
beacon.gpsAmbiguity = data["beacon"]["gpsAmbiguity"] | false;
aprs_is.passcode = data["aprs_is"]["passcode"].as<String>();
aprs_is.server = data["aprs_is"]["server"].as<String>();
aprs_is.port = data["aprs_is"]["port"].as<int>();
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";
aprs_is.port = data["aprs_is"]["port"] | 14580;
aprs_is.filter = data["aprs_is"]["filter"] | "m/10";
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"] | false;
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"] | false;
loramodule.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
loramodule.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
loramodule.codingRate4 = data["lora"]["codingRate4"].as<int>();
loramodule.power = data["lora"]["power"].as<int>();
digi.mode = data["digi"]["mode"] | 0;
digi.ecoMode = data["digi"]["ecoMode"] | 0;
if (digi.ecoMode == 1) shouldSleepStop = false;
display.alwaysOn = data["display"]["alwaysOn"].as<bool>();
display.timeout = data["display"]["timeout"].as<int>();
display.turn180 = data["display"]["turn180"].as<bool>();
loramodule.txFreq = data["lora"]["txFreq"] | 433775000;
loramodule.rxFreq = data["lora"]["rxFreq"] | 433775000;
loramodule.spreadingFactor = data["lora"]["spreadingFactor"] | 12;
loramodule.signalBandwidth = data["lora"]["signalBandwidth"] | 125000;
loramodule.codingRate4 = data["lora"]["codingRate4"] | 5;
loramodule.power = data["lora"]["power"] | 20;
loramodule.txActive = data["lora"]["txActive"] | false;
loramodule.rxActive = data["lora"]["rxActive"] | false;
syslog.active = data["syslog"]["active"].as<bool>();
syslog.server = data["syslog"]["server"].as<String>();
syslog.port = data["syslog"]["port"].as<int>();
display.alwaysOn = data["display"]["alwaysOn"] | true;
display.timeout = data["display"]["timeout"] | 4;
display.turn180 = data["display"]["turn180"] | false;
bme.active = data["bme"]["active"].as<bool>();
bme.heightCorrection = data["bme"]["heightCorrection"].as<int>();
bme.temperatureCorrection = data["bme"]["temperatureCorrection"].as<float>();
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false;
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false;
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9;
ota.username = data["ota"]["username"].as<String>();
ota.password = data["ota"]["password"].as<String>();
battery.sendExternalVoltage = data["battery"]["sendExternalVoltage"] | false;
battery.externalVoltagePin = data["battery"]["externalVoltagePin"] | 34;
battery.monitorExternalVoltage = data["battery"]["monitorExternalVoltage"] | false;
battery.externalSleepVoltage = data["battery"]["externalSleepVoltage"] | 10.9;
battery.voltageDividerR1 = data["battery"]["voltageDividerR1"] | 100.0;
battery.voltageDividerR2 = data["battery"]["voltageDividerR2"] | 27.0;
tnc.enableServer = data["tnc"]["enableServer"].as<bool>();
tnc.enableSerial = data["tnc"]["enableSerial"].as<bool>();
tnc.acceptOwn = data["tnc"]["acceptOwn"].as<bool>();
battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false;
lowPowerMode = data["other"]["lowPowerMode"].as<bool>();
lowVoltageCutOff = data["other"]["lowVoltageCutOff"].as<double>();
wxsensor.active = data["wxsensor"]["active"] | false;
wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0;
wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0;
backupDigiMode = data["other"]["backupDigiMode"].as<bool>();
syslog.active = data["syslog"]["active"] | false;
syslog.server = data["syslog"]["server"] | "lora.link9.net";
syslog.port = data["syslog"]["port"] | 1514;
rebootMode = data["other"]["rebootMode"].as<bool>();
rebootModeTime = data["other"]["rebootModeTime"].as<int>();
tnc.enableServer = data["tnc"]["enableServer"] | false;
tnc.enableSerial = data["tnc"]["enableSerial"] | false;
tnc.acceptOwn = data["tnc"]["acceptOwn"] | false;
int stationMode = data["stationMode"].as<int>(); // deprecated but need to specify config version
ota.username = data["ota"]["username"] | "";
ota.password = data["ota"]["password"] | "";
if (stationMode == 0) {
// Load new settings
webadmin.active = data["webadmin"]["active"] | false;
webadmin.username = data["webadmin"]["username"] | "admin";
webadmin.password = data["webadmin"]["password"] | "";
beacon.latitude = data["beacon"]["latitude"].as<double>();
beacon.longitude = data["beacon"]["longitude"].as<double>();
beacon.comment = data["beacon"]["comment"].as<String>();
beacon.overlay = data["beacon"]["overlay"].as<String>();
beacon.symbol = data["beacon"]["symbol"].as<String>();
beacon.interval = data["beacon"]["interval"].as<int>();
beacon.sendViaAPRSIS = data["beacon"]["sendViaAPRSIS"].as<bool>();
beacon.sendViaRF = data["beacon"]["sendViaRF"].as<bool>();
beacon.path = data["beacon"]["path"].as<String>();
ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0;
digi.mode = data["digi"]["mode"].as<int>();
backupDigiMode = data["other"]["backupDigiMode"] | false;
aprs_is.active = data["aprs_is"]["active"].as<bool>();
aprs_is.filter = data["aprs_is"]["filter"].as<String>();
aprs_is.messagesToRF = data["aprs_is"]["messagesToRF"].as<bool>();
aprs_is.objectsToRF = data["aprs_is"]["objectsToRF"].as<bool>();
rebootMode = data["other"]["rebootMode"] | false;
rebootModeTime = data["other"]["rebootModeTime"] | 6;
loramodule.txFreq = data["lora"]["txFreq"].as<long>();
loramodule.rxFreq = data["lora"]["rxFreq"].as<long>();
loramodule.txActive = data["lora"]["txActive"].as<bool>();
loramodule.rxActive = data["lora"]["rxActive"].as<bool>();
} else {
// Load old settings and put into new variables not actual config
personalNote = data["personalNote"] | "personal note here";
String iGateComment = data["iGateComment"].as<String>();
int beaconInterval = data["other"]["beaconInterval"].as<int>();
blacklist = data["blacklist"] | "station callsign";
long iGateFreq = data["lora"]["iGateFreq"].as<long>();
long digirepeaterTxFreq = data["lora"]["digirepeaterTxFreq"].as<long>();
long digirepeaterRxFreq = data["lora"]["digirepeaterRxFreq"].as<long>();
String digiComment = data["digi"]["comment"].as<String>();
double digiLatitude = data["digi"]["latitude"].as<double>();
double digiLongitude = data["digi"]["longitude"].as<double>();
beacon.latitude = digiLatitude;
beacon.longitude = digiLongitude;
beacon.interval = beaconInterval;
loramodule.txFreq = digirepeaterTxFreq;
loramodule.rxFreq = digirepeaterRxFreq;
loramodule.rxActive = true;
beacon.sendViaAPRSIS = true;
beacon.sendViaRF = false;
switch (stationMode) {
case 1: // IGate only
// aprs_is.active = true; // better don't do that automatically
beacon.comment = iGateComment;
loramodule.rxFreq = iGateFreq;
break;
case 5: // Digi + IGate
case 2: // Digi + IGate
// aprs_is.active = true; // better don't do that automatically
// digi.mode = 2; // better don't do that automatically
beacon.comment = digiComment;
loramodule.rxFreq = iGateFreq;
break;
case 3: // Digi
case 4: // Digi
// digi.mode = 2; // better don't do that automatically
beacon.comment = digiComment;
break;
}
reload = true;
}
remoteManagement.managers = data["remoteManagement"]["managers"] | "";
remoteManagement.rfOnly = data["remoteManagement"]["rfOnly"] | true;
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;
@@ -269,86 +247,102 @@ bool Configuration::readFile() {
}
void Configuration::init() {
reload = false;
WiFi_AP wifiap;
wifiap.ssid = "";
wifiap.password = "";
wifiap.ssid = "";
wifiap.password = "";
wifiAPs.push_back(wifiap);
wifiAutoAP.password = "1234567890";
wifiAutoAP.powerOff = 15;
wifiAutoAP.password = "1234567890";
wifiAutoAP.timeout = 10;
callsign = "N0CALL";
callsign = "N0CALL-10";
beacon.comment = "LoRa APRS"; // new
beacon.latitude = 0.0; // new
beacon.longitude = 0.0; // new
beacon.interval = 15; // new
beacon.overlay = "L"; // new
beacon.symbol = "#"; // new
beacon.sendViaAPRSIS = true; // new
beacon.sendViaRF = false; // new
beacon.path = "WIDE1-1"; // new
digi.mode = 0;
beacon.comment = "LoRa APRS";
beacon.latitude = 0.0;
beacon.longitude = 0.0;
beacon.interval = 15;
beacon.overlay = "L";
beacon.symbol = "a";
beacon.sendViaAPRSIS = true;
beacon.sendViaRF = false;
beacon.path = "WIDE1-1";
tnc.enableServer = false;
tnc.enableSerial = false;
tnc.acceptOwn = false;
beacon.gpsActive = false;
beacon.gpsAmbiguity = false;
aprs_is.active = false; // new
aprs_is.passcode = "XYZVW";
aprs_is.server = "rotate.aprs2.net";
aprs_is.port = 14580;
aprs_is.filter = "m/10"; // new
aprs_is.messagesToRF = false;
aprs_is.objectsToRF = false;
digi.mode = 0;
digi.ecoMode = 0;
loramodule.txFreq = 433775000; // new
loramodule.rxFreq = 433775000; // new
loramodule.spreadingFactor = 12;
loramodule.signalBandwidth = 125000;
loramodule.codingRate4 = 5;
loramodule.power = 20;
loramodule.txActive = false; // new
loramodule.rxActive = true; // new
tnc.enableServer = false;
tnc.enableSerial = false;
tnc.acceptOwn = false;
display.alwaysOn = true;
display.timeout = 4;
display.turn180 = false;
aprs_is.active = false;
aprs_is.passcode = "XYZVW";
aprs_is.server = "rotate.aprs2.net";
aprs_is.port = 14580;
aprs_is.filter = "m/10";
aprs_is.messagesToRF = false;
aprs_is.objectsToRF = false;
syslog.active = false;
syslog.server = "192.168.0.100";
syslog.port = 514;
loramodule.txFreq = 433775000;
loramodule.rxFreq = 433775000;
loramodule.spreadingFactor = 12;
loramodule.signalBandwidth = 125000;
loramodule.codingRate4 = 5;
loramodule.power = 20;
loramodule.txActive = false;
loramodule.rxActive = true;
bme.active = false;
bme.heightCorrection = 0;
bme.temperatureCorrection = 0.0;
display.alwaysOn = true;
display.timeout = 4;
display.turn180 = false;
ota.username = "";
ota.password = "";
syslog.active = false;
syslog.server = "lora.link9.net";
syslog.port = 1514;
rememberStationTime = 30;
wxsensor.active = false;
wxsensor.heightCorrection = 0;
wxsensor.temperatureCorrection = 0.0;
ota.username = "";
ota.password = "";
rememberStationTime = 30;
battery.sendInternalVoltage = false;
battery.monitorInternalVoltage = false;
battery.internalSleepVoltage = 3.0;
battery.internalSleepVoltage = 2.9;
battery.sendExternalVoltage = false;
battery.externalVoltagePin = 34;
battery.monitorExternalVoltage = false;
battery.externalSleepVoltage = 3.0;
battery.externalSleepVoltage = 10.9;
battery.voltageDividerR1 = 100.0;
battery.voltageDividerR2 = 27.0;
lowPowerMode = false;
lowVoltageCutOff = 0;
battery.sendVoltageAsTelemetry = false;
backupDigiMode = false;
backupDigiMode = false;
rebootMode = false;
rebootModeTime = 0;
rebootMode = false;
rebootModeTime = 0;
personalNote = "";
blacklist = "";
webadmin.active = false;
webadmin.username = "admin";
webadmin.password = "";
ntp.gmtCorrection = 0.0;
remoteManagement.managers = "";
remoteManagement.rfOnly = true;
Serial.println("All is Written!");
}

View File

@@ -2,13 +2,14 @@
#include "configuration.h"
#include "station_utils.h"
#include "aprs_is_utils.h"
#include "query_utils.h"
#include "digi_utils.h"
#include "wifi_utils.h"
#include "lora_utils.h"
#include "gps_utils.h"
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern uint32_t lastScreenOn;
extern String iGateBeaconPacket;
@@ -24,20 +25,55 @@ extern bool backUpDigiMode;
namespace DIGI_Utils {
String buildPacket(const String& path, const String& packet, bool thirdParty) {
String packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
String tempPath = path;
tempPath.replace(Config.beacon.path, Config.callsign + "*");
packetToRepeat += tempPath;
if (thirdParty) {
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":}")));
} else {
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(":")));
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;
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");
} else {
return "";
}
}
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 += ",";
packetToRepeat += Config.callsign;
packetToRepeat += "*";
packetToRepeat += APRS_IS_Utils::checkForStartingBytes(packet.substring(packet.indexOf(suffix)));
return packetToRepeat;
}
return packetToRepeat;
}
String generateDigiRepeatedPacket(const String& packet, bool thirdParty){
String generateDigipeatedPacket(const String& packet, bool thirdParty){
String temp;
if (thirdParty) { // only header is used
const String& header = packet.substring(0, packet.indexOf(":}"));
@@ -47,52 +83,74 @@ namespace DIGI_Utils {
}
if (temp.indexOf(",") > 2) { // checks for path
const String& path = temp.substring(temp.indexOf(",") + 1); // after tocall
if (path.indexOf(Config.beacon.path) != -1) {
return buildPacket(path, packet, thirdParty);
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-");
// 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 "";
}
} 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 {
return "";
}
}
void processLoRaPacket(const String& packet) {
if (packet != "") {
if ((packet.substring(0, 3) == "\x3c\xff\x01") && (packet.indexOf("NOGATE") == -1)) {
bool thirdPartyPacket = false;
String temp, Sender;
if (packet.indexOf("}") > 0 && 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 (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 (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);
}
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 = generateDigiRepeatedPacket(packet.substring(3), thirdPartyPacket);
if (loraPacket != "") {
STATION_Utils::addToOutputPacketBuffer(loraPacket);
display_toggle(true);
lastScreenOn = millis();
}
}
if (!queryMessage) {
String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
if (loraPacket != "") {
STATION_Utils::addToOutputPacketBuffer(loraPacket);
if (Config.digi.ecoMode != 1) displayToggle(true);
lastScreenOn = millis();
}
}
}

View File

@@ -1,6 +1,6 @@
#include <Wire.h>
#include "configuration.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "display.h"
@@ -9,33 +9,47 @@
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite sprite = TFT_eSprite(&tft);
#ifdef HELTEC_WIRELESS_TRACKER
#define bigSizeFont 2
#define smallSizeFont 1
#define lineSpacing 9
#define lineSpacing 10
#endif
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
#define bigSizeFont 5
#define smallSizeFont 2
#define lineSpacing 25
#endif
uint16_t redColor = 0xc8a2;
#else
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#if defined(HELTEC_V3)
#define OLED_DISPLAY_HAS_RST_PIN
#ifdef HAS_EPAPER
#include <heltec-eink-modules.h>
#include "Fonts/FreeSansBold9pt7b.h"
EInkDisplay_WirelessPaperV1_1 display;
String lastEpaperText;
#else
#include <Adafruit_GFX.h>
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
#include <Adafruit_SH110X.h>
Adafruit_SH1106G display(128, 64, &Wire, OLED_RST);
#else
#include <Adafruit_SSD1306.h>
#ifdef HELTEC_WSL_V3_DISPLAY
Adafruit_SSD1306 display(128, 64, &Wire1, OLED_RST);
#else
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST);
#endif
#endif
#endif
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST);
#endif
#endif
extern Configuration Config;
extern Configuration Config;
String oldHeader, oldFirstLine, oldSecondLine, oldThirdLine, oldFourthLine, oldFifthLine, oldSixthLine;
bool displayFound = false;
void cleanTFT() {
#ifdef HAS_TFT
tft.fillScreen(TFT_BLACK);
#endif
}
void setup_display() {
void displaySetup() {
#ifdef HAS_DISPLAY
delay(500);
#ifdef HAS_TFT
@@ -46,145 +60,222 @@ void setup_display() {
} else {
tft.setRotation(1);
}
pinMode(TFT_BL, OUTPUT);
digitalWrite(TFT_BL, HIGH);
tft.setTextFont(0);
tft.fillScreen(TFT_BLACK);
#else
#ifdef OLED_DISPLAY_HAS_RST_PIN
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
sprite.createSprite(320,240);
#else
sprite.createSprite(160,80);
#endif
Wire.begin(OLED_SDA, OLED_SCL);
#else
#ifdef HAS_EPAPER
display.landscape();
display.printCenter("LoRa APRS iGate Initialising...");
display.update();
#else
#ifdef OLED_DISPLAY_HAS_RST_PIN
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
delay(20);
digitalWrite(OLED_RST, HIGH);
#endif
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
if (Config.display.turn180) {
display.setRotation(2);
}
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
display.display();
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
if (!display.begin(0x3c, false)) {
displayFound = true;
if (Config.display.turn180) display.setRotation(2);
display.clearDisplay();
display.setTextColor(SH110X_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.setContrast(1);
display.display();
}
#else
if(display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
displayFound = true;
if (Config.display.turn180) display.setRotation(2);
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
display.display();
}
#endif
#endif
#endif
delay(1000);
#endif
}
void display_toggle(bool toggle) {
void displayToggle(bool toggle) {
#ifdef HAS_DISPLAY
if (toggle) {
#ifdef HAS_TFT
digitalWrite(TFT_BL, HIGH);
#else
display.ssd1306_command(SSD1306_DISPLAYON);
#ifdef HAS_EPAPER
display.printCenter("EPAPER Display Disabled by toggle...");
display.update();
#else
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
if (displayFound) display.oled_command(SH110X_DISPLAYON);
#else
if (displayFound) display.ssd1306_command(SSD1306_DISPLAYON);
#endif
#endif
#endif
} else {
#ifdef HAS_TFT
digitalWrite(TFT_BL, LOW);
#else
display.ssd1306_command(SSD1306_DISPLAYOFF);
#ifdef HAS_EPAPER
display.printCenter("Enabled EPAPER Display...");
display.update();
#else
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
if (displayFound) display.oled_command(SH110X_DISPLAYOFF);
#else
if (displayFound) display.ssd1306_command(SSD1306_DISPLAYOFF);
#endif
#endif
#endif
}
#endif
}
bool shouldCleanTFT(const String& header, const String& line1, const String& line2, const String& line3) {
if (oldHeader != header || oldFirstLine != line1 || oldSecondLine != line2 || oldThirdLine != line3) {
oldHeader = header;
oldFirstLine = line1;
oldSecondLine = line2;
oldThirdLine = line3;
return true;
} else {
return false;
}
}
bool shouldCleanTFT(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6) {
if (oldHeader != header || oldFirstLine != line1 || oldSecondLine != line2 || oldThirdLine != line3 || oldFourthLine != line4 || oldFifthLine != line5 || oldSixthLine != line6) {
oldHeader = header;
oldFirstLine = line1;
oldSecondLine = line2;
oldThirdLine = line3;
oldFourthLine = line4;
oldFifthLine = line5;
oldSixthLine = line6;
return true;
} else {
return false;
}
}
void show_display(const String& header, const String& line1, const String& line2, const String& line3, int wait) {
void displayShow(const String& header, const String& line1, const String& line2, const String& line3, int wait) {
#ifdef HAS_DISPLAY
const String* const lines[] = {&line1, &line2, &line3};
#ifdef HAS_TFT
if (shouldCleanTFT(header, line1, line2, line3)) {
cleanTFT();
}
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.setTextSize(bigSizeFont);
tft.setCursor(0, 0);
tft.print(header);
tft.setTextSize(smallSizeFont);
sprite.fillSprite(TFT_BLACK);
#if defined(HELTEC_WIRELESS_TRACKER)
sprite.fillRect(0, 0, 160, 19, redColor);
#endif
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
sprite.fillRect(0, 0, 320, 43, redColor);
#endif
sprite.setTextFont(0);
sprite.setTextSize(bigSizeFont);
sprite.setTextColor(TFT_WHITE, redColor);
sprite.drawString(header, 3, 3);
sprite.setTextSize(smallSizeFont);
sprite.setTextColor(TFT_WHITE, TFT_BLACK);
for (int i = 0; i < 3; i++) {
tft.setCursor(0, ((lineSpacing * (2 + i)) - 2));
tft.print(*lines[i]);
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
}
sprite.pushSprite(0,0);
#else
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(header);
for (int i = 0; i < 3; i++) {
display.setCursor(0, 8 + (8 * i));
display.println(*lines[i]);
}
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
display.display();
#ifdef HAS_EPAPER
display.clearMemory();
display.setCursor(5,10);
display.setFont(&FreeSansBold9pt7b);
display.println(header);
display.setFont(NULL);
for (int i = 0; i < 3; i++) {
display.setCursor(0, 25 + (14 * i));
display.println(*lines[i]);
}
display.update();
#else
if (displayFound) {
display.clearDisplay();
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
display.setTextColor(SH110X_WHITE);
#else
display.setTextColor(WHITE);
#endif
display.setTextSize(1);
display.setCursor(0, 0);
display.println(header);
for (int i = 0; i < 3; i++) {
display.setCursor(0, 8 + (8 * i));
display.println(*lines[i]);
}
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
display.setContrast(1);
#else
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
#endif
display.display();
}
#endif
#endif
delay(wait);
#endif
}
void show_display(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6, int wait) {
void displayShow(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6, int wait) {
#ifdef HAS_DISPLAY
const String* const lines[] = {&line1, &line2, &line3, &line4, &line5, &line6};
#ifdef HAS_TFT
if (shouldCleanTFT(header, line1, line2, line3, line4, line5, line6)) {
cleanTFT();
}
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.setTextSize(bigSizeFont);
tft.setCursor(0, 0);
tft.print(header);
tft.setTextSize(smallSizeFont);
sprite.fillSprite(TFT_BLACK);
#if defined(HELTEC_WIRELESS_TRACKER)
sprite.fillRect(0, 0, 160, 19, redColor);
#endif
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
sprite.fillRect(0, 0, 320, 43, redColor);
#endif
sprite.setTextFont(0);
sprite.setTextSize(bigSizeFont);
sprite.setTextColor(TFT_WHITE, redColor);
sprite.drawString(header, 3, 3);
sprite.setTextSize(smallSizeFont);
sprite.setTextColor(TFT_WHITE, TFT_BLACK);
for (int i = 0; i < 6; i++) {
tft.setCursor(0, ((lineSpacing * (2 + i)) - 2));
tft.print(*lines[i]);
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
}
sprite.pushSprite(0,0);
#else
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(0, 0);
display.println(header);
display.setTextSize(1);
for (int i = 0; i < 6; i++) {
display.setCursor(0, 16 + (8 * i));
display.println(*lines[i]);
}
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
display.display();
#ifdef HAS_EPAPER
lastEpaperText = header + line1 + line2 + line3 + line4 + line5 + line6;
display.clearMemory();
display.setCursor(5,10);
display.setFont(&FreeSansBold9pt7b);
display.println(header);
display.setFont(NULL);
for (int i = 0; i < 6; i++) {
display.setCursor(0, 25 + (14 * i));
display.println(*lines[i]);
}
display.update();
#else
if (displayFound) {
display.clearDisplay();
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
display.setTextColor(SH110X_WHITE);
#else
display.setTextColor(WHITE);
#endif
display.setTextSize(2);
display.setCursor(0, 0);
display.println(header);
display.setTextSize(1);
for (int i = 0; i < 6; i++) {
display.setCursor(0, 16 + (8 * i));
display.println(*lines[i]);
}
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
display.setContrast(1);
#else
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(1);
#endif
display.display();
}
#endif
#endif
delay(wait);
#endif

View File

@@ -1,18 +0,0 @@
#ifndef DISPLAY_H_
#define DISPLAY_H_
#include <Arduino.h>
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
void cleanTFT();
void setup_display();
void display_toggle(bool toggle);
bool shouldCleanTFT(const String& header, const String& line1, const String& line2, const String& line3);
bool shouldCleanTFT(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6);
void show_display(const String& header, const String& line1, const String& line2, const String& line3, int wait = 0);
void show_display(const String& header, const String& line1, const String& line2, const String& line3, const String& line4, const String& line5, const String& line6, int wait = 0);
#endif

View File

@@ -1,13 +1,22 @@
#include <TinyGPS++.h>
#include <WiFi.h>
#include "configuration.h"
#include "board_pinout.h"
#include "gps_utils.h"
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern WiFiClient espClient;
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
#ifdef GPS_BAUDRATE
#define GPS_BAUD GPS_BAUDRATE
#else
#define GPS_BAUD 9600
#endif
extern Configuration Config;
extern WiFiClient espClient;
extern HardwareSerial gpsSerial;
extern TinyGPSPlus gps;
String distance, iGateBeaconPacket, iGateLoRaBeaconPacket;
namespace GPS_Utils {
@@ -24,20 +33,32 @@ namespace GPS_Utils {
return(s);
}
float roundToTwoDecimals(float degrees) {
return round(degrees * 100) / 100;
}
String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol) {
String encodedData = overlay;
uint32_t aprs_lat, aprs_lon;
aprs_lat = 900000000 - latitude * 10000000;
float processedLatitude = latitude;
float processedLongitude = longitude;
if (Config.beacon.gpsActive && Config.beacon.gpsAmbiguity) {
processedLatitude = roundToTwoDecimals(latitude);
processedLongitude = roundToTwoDecimals(longitude);
}
aprs_lat = 900000000 - processedLatitude * 10000000;
aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615;
aprs_lon = 900000000 + longitude * 10000000 / 2;
aprs_lon = 900000000 + processedLongitude * 10000000 / 2;
aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615;
String Ns, Ew, helper;
if(latitude < 0) { Ns = "S"; } else { Ns = "N"; }
if(latitude < 0) { latitude= -latitude; }
if(processedLatitude < 0) { Ns = "S"; } else { Ns = "N"; }
if(processedLatitude < 0) { processedLatitude = -processedLatitude; }
if(longitude < 0) { Ew = "W"; } else { Ew = "E"; }
if(longitude < 0) { longitude= -longitude; }
if(processedLongitude < 0) { Ew = "W"; } else { Ew = "E"; }
if(processedLongitude < 0) { processedLongitude = -processedLongitude; }
char helper_base91[] = {"0000\0"};
int i;
@@ -50,28 +71,35 @@ namespace GPS_Utils {
encodedData += helper_base91[i];
}
encodedData += symbol;
encodedData += " x";
encodedData += " ";
encodedData += "\x47";
return encodedData;
}
void generateBeacons() {
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
show_display("***** ERROR ******", "CALLSIGN = NOT VALID!", " Use SSID 0-15", " Or Valid Callsign", 0);
while (true) {}
}
void generateBeaconFirstPart() {
String beaconPacket = Config.callsign;
beaconPacket += ">APLRG1";
if (Config.beacon.path.indexOf("WIDE") == 0) {
beaconPacket += ",";
beaconPacket += Config.beacon.path;
}
iGateBeaconPacket = beaconPacket;
iGateBeaconPacket += ",qAC:!";
iGateLoRaBeaconPacket = beaconPacket;
iGateLoRaBeaconPacket += ":!";
}
void generateBeacons() {
if (Config.callsign.indexOf("NOCALL-10") != 0 && !Utils::checkValidCallsign(Config.callsign)) {
displayShow("***** ERROR ******", "CALLSIGN = NOT VALID!", "", "Only Rx Mode Active", 3000);
Config.loramodule.txActive = false;
Config.aprs_is.messagesToRF = false;
Config.aprs_is.objectsToRF = false;
Config.beacon.sendViaRF = false;
Config.digi.mode = 0;
Config.backupDigiMode = false;
}
generateBeaconFirstPart();
String encodedGPS = encodeGPS(Config.beacon.latitude, Config.beacon.longitude, Config.beacon.overlay, Config.beacon.symbol);
iGateBeaconPacket += encodedGPS;
iGateLoRaBeaconPacket += encodedGPS;
@@ -82,22 +110,30 @@ namespace GPS_Utils {
}
String decodeEncodedGPS(const String& packet) {
const String& GPSPacket = packet.substring(packet.indexOf(":!")+3);
const String& encodedLatitude = GPSPacket.substring(0,4);
const String& encodedLongtitude = GPSPacket.substring(4,8);
const String& comment = GPSPacket.substring(12);
int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":=");
int Y1 = int(encodedLatitude[0]);
int Y2 = int(encodedLatitude[1]);
int Y3 = int(encodedLatitude[2]);
int Y4 = int(encodedLatitude[3]);
float decodedLatitude = 90.0 - ((((Y1-33) * pow(91,3)) + ((Y2-33) * pow(91,2)) + ((Y3-33) * 91) + Y4-33) / 380926.0);
int X1 = int(encodedLongtitude[0]);
int X2 = int(encodedLongtitude[1]);
int X3 = int(encodedLongtitude[2]);
int X4 = int(encodedLongtitude[3]);
float decodedLongitude = -180.0 + ((((X1-33) * pow(91,3)) + ((X2-33) * pow(91,2)) + ((X3-33) * 91) + X4-33) / 190463.0);
const uint8_t OFFSET = 3; // Offset for encoded data in the packet
String GPSPacket;
if (indexOfExclamation > 10) {
GPSPacket = packet.substring(indexOfExclamation + OFFSET);
} else if (indexOfEqual > 10) {
GPSPacket = packet.substring(indexOfEqual + OFFSET);
}
String encodedLatitude = GPSPacket.substring(0,4);
int Y1 = encodedLatitude[0] - 33;
int Y2 = encodedLatitude[1] - 33;
int Y3 = encodedLatitude[2] - 33;
int Y4 = encodedLatitude[3] - 33;
float decodedLatitude = 90.0 - (((Y1 * pow(91,3)) + (Y2 * pow(91,2)) + (Y3 * 91) + Y4) / 380926.0);
String encodedLongitude = GPSPacket.substring(4,8);
int X1 = encodedLongitude[0] - 33;
int X2 = encodedLongitude[1] - 33;
int X3 = encodedLongitude[2] - 33;
int X4 = encodedLongitude[3] - 33;
float decodedLongitude = -180.0 + (((X1 * pow(91,3)) + (X2 * pow(91,2)) + (X3 * 91) + X4) / 190463.0);
distance = String(calculateDistanceTo(decodedLatitude, decodedLongitude),1);
@@ -108,6 +144,7 @@ namespace GPS_Utils {
decodedGPS += distance;
decodedGPS += "km";
String comment = GPSPacket.substring(12);
if (comment != "") {
decodedGPS += " / ";
decodedGPS += comment;
@@ -116,33 +153,30 @@ namespace GPS_Utils {
}
String getReceivedGPS(const String& packet) {
String infoGPS;
if (packet.indexOf(":!") > 10) {
infoGPS = packet.substring(packet.indexOf(":!") + 2);
} else if (packet.indexOf(":=") > 10) {
infoGPS = packet.substring(packet.indexOf(":=") + 2);
}
const String& Latitude = infoGPS.substring(0,8);
const String& Longitude = infoGPS.substring(9,18);
const String& comment = infoGPS.substring(19);
float convertedLatitude, convertedLongitude;
const String& firstLatPart = Latitude.substring(0,2);
const String& secondLatPart = Latitude.substring(2,4);
const String& thirdLatPart = Latitude.substring(Latitude.indexOf(".") + 1, Latitude.indexOf(".") + 3);
convertedLatitude = firstLatPart.toFloat() + (secondLatPart.toFloat()/60) + (thirdLatPart.toFloat()/(60*100));
int indexOfExclamation = packet.indexOf(":!");
int indexOfEqual = packet.indexOf(":=");
int indexOfAt = packet.indexOf(":@");
const String& firstLngPart = Longitude.substring(0,3);
const String& secondLngPart = Longitude.substring(3,5);
const String& thirdLngPart = Longitude.substring(Longitude.indexOf(".") + 1, Longitude.indexOf(".") + 3);
convertedLongitude = firstLngPart.toFloat() + (secondLngPart.toFloat()/60) + (thirdLngPart.toFloat()/(60*100));
if (String(Latitude[7]) == "S") {
convertedLatitude = -convertedLatitude;
}
if (String(Longitude[8]) == "W") {
convertedLongitude = -convertedLongitude;
String infoGPS;
if (indexOfExclamation > 10) {
infoGPS = packet.substring(indexOfExclamation + 2);
} else if (indexOfEqual > 10) {
infoGPS = packet.substring(indexOfEqual + 2);
} else if (indexOfAt > 10) {
infoGPS = packet.substring(indexOfAt + 9); // 9 = 2+7 (when 7 is timestamp characters)
}
String Latitude = infoGPS.substring(0,8); // First 8 characters are Latitude
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);
if (Latitude.endsWith("S")) convertedLatitude = -convertedLatitude; // Handle Southern Hemisphere
String Longitude = infoGPS.substring(9,18); // Next 9 characters are Longitude
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);
if (Longitude.endsWith("W")) convertedLongitude = -convertedLongitude; // Handle Western Hemisphere
distance = String(calculateDistanceTo(convertedLatitude, convertedLongitude),1);
@@ -153,6 +187,7 @@ namespace GPS_Utils {
decodedGPS += distance;
decodedGPS += "km";
String comment = infoGPS.substring(19);
if (comment != "") {
decodedGPS += " / ";
decodedGPS += comment;
@@ -161,21 +196,45 @@ namespace GPS_Utils {
}
String getDistanceAndComment(const String& packet) {
uint8_t encodedBytePosition = 0;
if (packet.indexOf(":!") > 10) {
encodedBytePosition = packet.indexOf(":!") + 14;
}
if (packet.indexOf(":=") > 10) {
encodedBytePosition = packet.indexOf(":=") + 14;
}
if (encodedBytePosition != 0) {
if (String(packet[encodedBytePosition]) == "G" || String(packet[encodedBytePosition]) == "Q" || String(packet[encodedBytePosition]) == "[" || String(packet[encodedBytePosition]) == "H") {
return decodeEncodedGPS(packet);
} else {
return getReceivedGPS(packet);
}
int indexOfAt = packet.indexOf(":@");
if (indexOfAt > 10) {
return getReceivedGPS(packet);
} else {
return " _ / _ / _ ";
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 (encodedBytePosition != 0) {
char currentChar = packet[encodedBytePosition];
if (currentChar == 'G' || currentChar == 'Q' || currentChar == '[' || currentChar == 'H' || currentChar == 'X') {
return decodeEncodedGPS(packet); // If valid encoded data position is found, decode it
} else {
return getReceivedGPS(packet);
}
} else {
return " _ / _ / _ ";
}
}
}
void setup() {
#ifdef HAS_GPS
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) {
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_TX, GPS_RX);
}
#endif
generateBeacons();
}
void getData() {
while (gpsSerial.available() > 0) {
gps.encode(gpsSerial.read());
}
}

View File

@@ -1,6 +1,7 @@
#include <Arduino.h>
#include "kiss_protocol.h"
bool validateTNC2Frame(const String& tnc2FormattedFrame) {
return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1);
}

View File

@@ -2,11 +2,14 @@
#include <WiFi.h>
#include "configuration.h"
#include "aprs_is_utils.h"
#include "boards_pinout.h"
#include "station_utils.h"
#include "board_pinout.h"
#include "syslog_utils.h"
#include "ntp_utils.h"
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern uint32_t lastRxTime;
@@ -18,22 +21,28 @@ bool transmitFlag = true;
#ifdef HAS_SX1262
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif
#ifdef HAS_SX1268
SX1268 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#if defined(LIGHTGATEWAY_1_0)
SPIClass loraSPI(FSPI);
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
#endif
#ifdef HAS_SX1278
SX1278 radio = new Module(RADIO_CS_PIN, RADIO_BUSY_PIN, RADIO_RST_PIN);
#endif
#ifdef HAS_SX1276
SX1276 radio = new Module(RADIO_CS_PIN, RADIO_BUSY_PIN, RADIO_RST_PIN);
#endif
#if defined(HAS_LLCC68) //LLCC68 supports spreading factor only in range of 5-11!
LLCC68 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif
int rssi, freqError;
float snr;
namespace LoRa_Utils {
void setFlag(void) {
@@ -41,21 +50,30 @@ namespace LoRa_Utils {
}
void setup() {
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
#ifdef LIGHTGATEWAY_1_0
pinMode(RADIO_VCC_PIN,OUTPUT);
digitalWrite(RADIO_VCC_PIN,HIGH);
loraSPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN, RADIO_CS_PIN);
#else
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
#endif
float freq = (float)Config.loramodule.rxFreq / 1000000;
#if defined(RADIO_HAS_XTAL)
radio.XTAL = true;
#endif
int state = radio.begin(freq);
if (state == RADIOLIB_ERR_NONE) {
Utils::println("Initializing LoRa Module");
} else {
Utils::println("Starting LoRa failed!");
Utils::println("Starting LoRa failed! State: " + String(state));
while (true);
}
#if defined(HAS_SX1262) || defined(HAS_SX1268)
if (!Config.lowPowerMode) {
radio.setDio1Action(setFlag);
} else {
#if defined(HAS_SX1262) || defined(HAS_SX1268) || defined(HAS_LLCC68)
//if (!Config.lowPowerMode) {
radio.setDio1Action(setFlag);
/*} else {
radio.setDIOMapping(1, RADIOLIB_SX126X_IRQ_RX_DONE);
}
}*/
#endif
#if defined(HAS_SX1278) || defined(HAS_SX1276)
radio.setDio0Action(setFlag, RISING);
@@ -66,11 +84,11 @@ namespace LoRa_Utils {
radio.setCodingRate(Config.loramodule.codingRate4);
radio.setCRC(true);
#if defined(RADIO_RXEN) && defined(RADIO_TXEN)
#if (defined(RADIO_RXEN) && defined(RADIO_TXEN)) || defined(LIGHTGATEWAY_1_0) // QRP Labs LightGateway has 400M22S (SX1268)
radio.setRfSwitchPins(RADIO_RXEN, RADIO_TXEN);
#endif
#ifdef HAS_1W_LORA // Ebyte E22 400M30S (SX1268) / 900M30S (SX1262)
#ifdef HAS_1W_LORA // Ebyte E22 400M30S (SX1268) / 900M30S (SX1262) / Ebyte E220 400M30S (LLCC68)
state = radio.setOutputPower(Config.loramodule.power); // max value 20dB for 1W modules as they have Low Noise Amp
radio.setCurrentLimit(140); // to be validated (100 , 120, 140)?
#endif
@@ -83,14 +101,14 @@ namespace LoRa_Utils {
radio.setCurrentLimit(140);
#endif
#if defined(HAS_SX1262) || defined(HAS_SX1268)
#if defined(HAS_SX1262) || defined(HAS_SX1268) || defined(HAS_LLCC68)
radio.setRxBoostedGainMode(true);
#endif
if (state == RADIOLIB_ERR_NONE) {
Utils::println("init : LoRa Module ... done!");
} else {
Utils::println("Starting LoRa failed!");
Utils::println("Starting LoRa failed! State: " + String(state));
while (true);
}
}
@@ -113,9 +131,9 @@ namespace LoRa_Utils {
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
changeFreqTx();
}
#ifdef INTERNAL_LED_PIN
digitalWrite(INTERNAL_LED_PIN, HIGH);
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;
@@ -123,36 +141,29 @@ namespace LoRa_Utils {
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX
}
Utils::print("---> LoRa Packet Tx : ");
Utils::print("---> LoRa Packet Tx : ");
Utils::println(newPacket);
} else {
Utils::print(F("failed, code "));
Utils::println(String(state));
}
#ifdef INTERNAL_LED_PIN
digitalWrite(INTERNAL_LED_PIN, LOW);
if (Config.digi.ecoMode != 1) digitalWrite(INTERNAL_LED_PIN, LOW); // disabled in Ultra Eco Mode
#endif
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
changeFreqRx();
}
}
/*String packetSanitization(const String& packet) {
String sanitizedPacket = packet;
if (packet.indexOf("\0") > 0) {
sanitizedPacket.replace("\0", "");
String receivePacketFromSleep() {
String packet = "";
int state = radio.readData(packet);
if (state == RADIOLIB_ERR_NONE) {
Utils::println("<--- LoRa Packet Rx : " + packet.substring(3));
} else {
packet = "";
}
if (packet.indexOf("\r") > 0) {
sanitizedPacket.replace("\r", "");
}
if (packet.indexOf("\n") > 0) {
sanitizedPacket.replace("\n", "");
}
return sanitizedPacket;
}*/
void startReceive() {
radio.startReceive();
return packet;
}
String receivePacket() {
@@ -166,30 +177,36 @@ namespace LoRa_Utils {
int state = radio.readData(packet);
if (state == RADIOLIB_ERR_NONE) {
if (packet != "") {
rssi = radio.getRSSI();
snr = radio.getSNR();
freqError = radio.getFrequencyError();
Utils::println("<--- LoRa Packet Rx : " + packet.substring(3));
Utils::println("(RSSI:" + String(rssi) + " / SNR:" + String(snr) + " / FreqErr:" + String(freqError) + ")");
if (!Config.lowPowerMode) {
ReceivedPacket receivedPacket;
receivedPacket.millis = millis();
receivedPacket.packet = packet.substring(3);
receivedPacket.RSSI = rssi;
receivedPacket.SNR = snr;
if (receivedPackets.size() >= 20) {
receivedPackets.erase(receivedPackets.begin());
String sender = packet.substring(3, packet.indexOf(">"));
if (packet.substring(0,3) == "\x3c\xff\x01" && !STATION_Utils::isBlacklisted(sender)){ // avoid processing BlackListed stations
rssi = radio.getRSSI();
snr = radio.getSNR();
freqError = radio.getFrequencyError();
Utils::println("<--- LoRa Packet Rx : " + packet.substring(3));
Utils::println("(RSSI:" + String(rssi) + " / SNR:" + String(snr) + " / FreqErr:" + String(freqError) + ")");
if (Config.digi.ecoMode == 0) {
if (receivedPackets.size() >= 10) {
receivedPackets.erase(receivedPackets.begin());
}
ReceivedPacket receivedPacket;
receivedPacket.rxTime = NTP_Utils::getFormatedTime();
receivedPacket.packet = packet.substring(3);
receivedPacket.RSSI = rssi;
receivedPacket.SNR = snr;
receivedPackets.push_back(receivedPacket);
}
receivedPackets.push_back(receivedPacket);
}
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX
}
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
SYSLOG_Utils::log(1, packet, rssi, snr, freqError); // RX
}
} else {
packet = "";
}
lastRxTime = millis();
return packet;
}
}
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
rssi = radio.getRSSI();
snr = radio.getSNR();
@@ -209,6 +226,10 @@ namespace LoRa_Utils {
return packet;
}
void wakeRadio() {
radio.startReceive();
}
void sleepRadio() {
radio.sleep();
}

34
src/ntp_utils.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <WiFi.h>
#include "configuration.h"
#include "ntp_utils.h"
#include "time.h"
extern Configuration Config;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 15 * 60 * 1000); // Update interval 15 min
namespace NTP_Utils {
void setup() {
if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") {
int gmt = Config.ntp.gmtCorrection * 3600;
timeClient.setTimeOffset(gmt);
timeClient.begin();
}
}
void update() {
if (WiFi.status() == WL_CONNECTED && Config.digi.ecoMode == 0 && Config.callsign != "NOCALL-10") timeClient.update();
}
String getFormatedTime() {
if (Config.digi.ecoMode == 0) return timeClient.getFormattedTime();
return "DigiEcoMode Active";
}
}

View File

@@ -5,6 +5,7 @@
#include "ota_utils.h"
#include "display.h"
extern Configuration Config;
extern uint32_t lastScreenOn;
extern bool isUpdatingOTA;
@@ -29,32 +30,32 @@ namespace OTA_Utils {
void onOTAStart() {
Serial.println("OTA update started!");
display_toggle(true);
displayToggle(true);
lastScreenOn = millis();
show_display("", "", "", " OTA update started!", "", "", "", 1000);
displayShow("", "", "", " OTA update started!", "", "", "", 1000);
isUpdatingOTA = true;
}
void onOTAProgress(size_t current, size_t final) {
if (millis() - ota_progress_millis > 1000) {
display_toggle(true);
displayToggle(true);
lastScreenOn = millis();
ota_progress_millis = millis();
Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final);
show_display("", "", " OTA Progress : " + String((current*100)/final) + "%", "", "", "", "", 100);
displayShow("", "", " OTA Progress : " + String((current*100)/final) + "%", "", "", "", "", 100);
}
}
void onOTAEnd(bool success) {
display_toggle(true);
displayToggle(true);
lastScreenOn = millis();
if (success) {
Serial.println("OTA update finished successfully!");
show_display("", "", " OTA update success!", "", " Rebooting ...", "", "", 4000);
} else {
Serial.println("There was an error during OTA update!");
show_display("", "", " OTA update fail!", "", "", "", "", 4000);
}
String statusMessage = success ? "OTA update success!" : "OTA update fail!";
String rebootMessage = success ? "Rebooting ..." : "";
Serial.println(success ? "OTA update finished successfully!" : "There was an error during OTA update!");
displayShow("", "", statusMessage, "", rebootMessage, "", "", 4000);
isUpdatingOTA = false;
}

View File

@@ -1,12 +1,20 @@
#include "configuration.h"
#include "battery_utils.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "power_utils.h"
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
#define I2C_SDA 21
#define I2C_SCL 22
#define IRQ_PIN 35
#ifdef TTGO_T_Beam_S3_SUPREME_V3
#define I2C0_SDA 17
#define I2C0_SCL 18
#define I2C1_SDA 42
#define I2C1_SCL 41
#define IRQ_PIN 40
#else
#define I2C_SDA 21
#define I2C_SCL 22
#define IRQ_PIN 35
#endif
#endif
#ifdef HAS_AXP192
@@ -47,14 +55,58 @@ namespace POWER_Utils {
#endif
}
void activateGPS() {
#ifdef HAS_AXP192
PMU.setLDO3Voltage(3300);
PMU.enableLDO3();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO4Voltage(3300);
PMU.enableALDO4();
#else
PMU.setALDO3Voltage(3300);
PMU.enableALDO3();
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, HIGH);
#endif
//gpsIsActive = true;
}
void deactivateGPS() {
#ifdef HAS_AXP192
PMU.disableLDO3();
#endif
#ifdef HAS_AXP2101
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO4();
#else
PMU.disableALDO3();
#endif
#endif
#ifdef HELTEC_WIRELESS_TRACKER
digitalWrite(VEXT_CTRL, LOW);
#endif
//gpsIsActive = false;
}
void activateLoRa() {
#ifdef HAS_AXP192
PMU.setLDO2Voltage(3300);
PMU.enableLDO2();
#endif
#ifdef HAS_AXP2101
PMU.setALDO2Voltage(3300);
PMU.enableALDO2();
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO3Voltage(3300);
PMU.enableALDO3();
#else
PMU.setALDO2Voltage(3300);
PMU.enableALDO2();
#endif
#endif
}
@@ -63,7 +115,11 @@ namespace POWER_Utils {
PMU.disableLDO2();
#endif
#ifdef HAS_AXP2101
PMU.disableALDO2();
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO3();
#else
PMU.disableALDO2();
#endif
#endif
}
@@ -81,20 +137,29 @@ namespace POWER_Utils {
}
return result;
#elif defined(HAS_AXP2101)
bool result = PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
#ifdef TTGO_T_Beam_S3_SUPREME_V3
bool result = PMU.begin(Wire1, AXP2101_SLAVE_ADDRESS, I2C1_SDA, I2C1_SCL);
#else
bool result = PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
#endif
if (result) {
PMU.disableDC2();
PMU.disableDC3();
PMU.disableDC4();
PMU.disableDC5();
PMU.disableALDO1();
PMU.disableALDO4();
#ifndef TTGO_T_Beam_S3_SUPREME_V3
PMU.disableALDO1();
PMU.disableALDO4();
#endif
PMU.disableBLDO1();
PMU.disableBLDO2();
PMU.disableDLDO1();
PMU.disableDLDO2();
PMU.setDC1Voltage(3300);
PMU.enableDC1();
#ifdef TTGO_T_Beam_S3_SUPREME_V3
PMU.setALDO1Voltage(3300);
#endif
PMU.setButtonBatteryChargeVoltage(3300);
PMU.enableButtonBatteryCharge();
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
@@ -122,8 +187,16 @@ namespace POWER_Utils {
#endif
#ifdef HAS_AXP2101
Wire.begin(SDA, SCL);
if (begin(Wire)) {
bool beginStatus = false;
#ifdef TTGO_T_Beam_S3_SUPREME_V3
Wire1.begin(I2C1_SDA, I2C1_SCL);
Wire.begin(I2C0_SDA, I2C0_SCL);
if (begin(Wire1)) beginStatus = true;
#else
Wire.begin(SDA, SCL);
if (begin(Wire)) beginStatus = true;
#endif
if (beginStatus) {
Serial.println("AXP2101 init done!");
} else {
Serial.println("AXP2101 init failed!");
@@ -150,27 +223,57 @@ namespace POWER_Utils {
}
#ifdef VEXT_CTRL
pinMode(VEXT_CTRL,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
#ifndef HELTEC_WSL_V3
digitalWrite(VEXT_CTRL, HIGH);
#endif
if (Config.digi.ecoMode != 1) {
pinMode(VEXT_CTRL,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3)
digitalWrite(VEXT_CTRL, HIGH);
#endif
#if defined(HELTEC_WP) || defined(HELTEC_WS) || defined(HELTEC_V3_2)
digitalWrite(VEXT_CTRL, LOW);
#endif
}
#endif
#ifdef HAS_GPS
if (Config.beacon.gpsActive && Config.digi.ecoMode != 1) activateGPS();
#endif
#ifdef ADC_CTRL
pinMode(ADC_CTRL, OUTPUT);
#endif
#ifdef HELTEC_WIRELESS_TRACKER
#if defined(HELTEC_WIRELESS_TRACKER)
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#ifdef HELTEC_V3
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WS) || defined(LIGHTGATEWAY_1_0) || defined(TTGO_LORA32_T3S3_V1_2) || defined(HELTEC_V2)
Wire.begin(OLED_SDA, OLED_SCL);
#endif
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WP) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
Wire1.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
pinMode(BOARD_POWERON, OUTPUT);
digitalWrite(BOARD_POWERON, HIGH);
pinMode(BOARD_SDCARD_CS, OUTPUT);
pinMode(RADIO_CS_PIN, OUTPUT);
pinMode(TFT_CS, OUTPUT);
digitalWrite(BOARD_SDCARD_CS, HIGH);
digitalWrite(RADIO_CS_PIN, HIGH);
digitalWrite(TFT_CS, HIGH);
delay(500);
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
#endif
delay(1000);
BATTERY_Utils::setup();
BATTERY_Utils::startupBatteryHealth();
setCpuFrequencyMhz(80);
}
}

View File

@@ -1,73 +1,146 @@
#include "configuration.h"
#include "battery_utils.h"
#include "station_utils.h"
#include "query_utils.h"
#include "lora_utils.h"
extern Configuration Config;
extern std::vector<String> lastHeardStation;
extern String versionDate;
extern int rssi;
extern float snr;
extern int freqError;
extern Configuration Config;
extern std::vector<LastHeardStation> lastHeardStations;
extern String versionDate;
extern int rssi;
extern float snr;
extern int freqError;
extern bool shouldSleepLowVoltage;
extern bool saveNewDigiEcoModeConfig;
namespace QUERY_Utils {
String process(const String& query, const String& station, const uint8_t queryOrigin) {
String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty) {
String answer;
if (query=="?APRS?" || query=="?aprs?" || query=="?Aprs?" || query=="H" || query=="h" || query=="HELP" || query=="Help" || query=="help" || query=="?") {
answer.concat("?APRSV ?APRSP ?APRSL ?APRSH ?WHERE callsign");
} else if (query=="?APRSV" || query=="?aprsv" || query=="?Aprsv") {
answer = "CA2RXU_LoRa_iGate 1.3 v";
String queryQuestion = query;
queryQuestion.toUpperCase();
if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") {
answer.concat("?APRSV ?APRSP ?APRSL ?APRSSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign
} else if (queryQuestion == "?APRSV") {
answer.concat("CA2RXU_LoRa_iGate 2.3 v");
answer.concat(versionDate);
} else if (query=="?APRSP" || query=="?aprsp" || query=="?Aprsp") {
answer = "iGate QTH: ";
answer.concat(String(Config.beacon.latitude,2));
} else if (queryQuestion == "?APRSP") {
answer.concat("iGate QTH: ");
answer.concat(String(Config.beacon.latitude,3));
answer.concat(" ");
answer.concat(String(Config.beacon.longitude,2));
} else if (query=="?APRSL" || query=="?aprsl" || query=="?Aprsl") {
if (lastHeardStation.size() == 0) {
answer.concat(String(Config.beacon.longitude,3));
} else if (queryQuestion == "?APRSL") {
if (lastHeardStations.size() == 0) {
char answerArray[50];
snprintf(answerArray, sizeof(answerArray), "No Station Listened in the last %d min.", Config.rememberStationTime);
answer.concat(answerArray);
} else {
for (int i=0; i<lastHeardStation.size(); i++) {
answer += lastHeardStation[i].substring(0,lastHeardStation[i].indexOf(",")) + " ";
for (int i=0; i<lastHeardStations.size(); i++) {
answer += lastHeardStations[i].station + " ";
}
answer.trim();
}
} else if (query=="?APRSSR" || query=="?aprssr" || query=="?Aprssr") {
} else if (queryQuestion == "?APRSSR") {
char signalData[35];
snprintf(signalData, sizeof(signalData), " %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
answer.concat(signalData);
} else if (query.indexOf("?APRSH") == 0 || query.indexOf("?aprsh") == 0 || query.indexOf("?Aprsh") == 0) {
} /*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 (query.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) { // Exit Digipeater EcoMode
answer = "DigiEcoMode:OFF";
Config.digi.ecoMode = 0;
Config.display.alwaysOn = true;
Config.display.timeout = 10;
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sended before restart.
saveNewDigiEcoModeConfig = true;
} else {
answer = "DigiEcoMode was OFF";
}
} else {
answer = "DigiEcoMode 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
answer = "DigiEcoMode:ON";
Config.digi.ecoMode = 1;
shouldSleepLowVoltage = true; // to make sure all packets in outputPacketBuffer are sended before restart.
saveNewDigiEcoModeConfig = true;
} else {
answer = "DigiEcoMode was ON";
}
} else {
answer = "DigiEcoMode 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.indexOf("?TX=ON") == 0) {
if (Config.loramodule.txActive) {
answer = "TX was ON";
} else {
Config.loramodule.txActive = true;
answer = "TX=ON";
}
} else if (queryQuestion.indexOf("?TX=OFF") == 0) {
if (!Config.loramodule.txActive) {
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
answer = "New Config Saved";
Config.writeFile();
}
}
if (answer == "") return "";
String queryAnswer = Config.callsign;
queryAnswer += ">APLRG1";
if (queryFromAPRSIS) {
queryAnswer += ",TCPIP,qAC";
} else {
if (!thirdParty) queryAnswer += ",RFONLY";
if (Config.beacon.path != "") {
queryAnswer += ",";
queryAnswer += Config.beacon.path;
}
}
queryAnswer += "::";
String processedStation = station;
for (int i = station.length(); i < 9; i++) {
processedStation += ' ';
}
String queryAnswer = Config.callsign;
queryAnswer += ">APLRG1,";
if (queryOrigin == 1) { // from APRS-IS
queryAnswer += "TCPIP,qAC::";
} else { // else == 0 , from LoRa
if (Config.beacon.path == "") {
queryAnswer += "RFONLY::";
} else {
queryAnswer += "RFONLY,";
queryAnswer += Config.beacon.path;
queryAnswer += "::";
}
}
queryAnswer += processedStation;
queryAnswer += ":";
queryAnswer += answer;
queryAnswer += " *";
queryAnswer += char(random(97, 123));
queryAnswer += char(random(97, 123));
queryAnswer += "*";
return queryAnswer;
}

View File

@@ -1,13 +0,0 @@
#ifndef QUERY_UTILS_H_
#define QUERY_UTILS_H_
#include <Arduino.h>
namespace QUERY_Utils {
String process(const String& query, const String& station, const uint8_t queryOrigin);
}
#endif

63
src/sleep_utils.cpp Normal file
View File

@@ -0,0 +1,63 @@
#include "configuration.h"
#include "board_pinout.h"
#include "sleep_utils.h"
#include "digi_utils.h"
#include "lora_utils.h"
extern Configuration Config;
extern bool shouldSleepStop;
extern uint32_t lastBeaconTx;
bool wakeUpFlag = false;
namespace SLEEP_Utils {
void wakeUpLoRaPacketReceived() {
wakeUpFlag = true;
}
void checkWakeUpFlag() {
if (wakeUpFlag) {
String packet = LoRa_Utils::receivePacketFromSleep();
if (packet != "") {
DIGI_Utils::processLoRaPacket(packet);
}
wakeUpFlag = false;
}
}
void setup() {
if (Config.digi.ecoMode == 1) {
pinMode(RADIO_WAKEUP_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(RADIO_WAKEUP_PIN), wakeUpLoRaPacketReceived, RISING);
LoRa_Utils::wakeRadio();
#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) || 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(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)
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)
esp_deep_sleep_enable_gpio_wakeup(1ULL << GPIO_WAKEUP_PIN, ESP_GPIO_WAKEUP_GPIO_HIGH);
#endif
}
}
uint32_t getSecondsToSleep() {
uint32_t elapsedTime = (millis() - lastBeaconTx) / 1000; // in secs
uint32_t intervalTime = Config.beacon.interval * 60; // in secs
return (elapsedTime < intervalTime) ? (intervalTime - elapsedTime) : 0;
}
void startSleeping() {
if (!shouldSleepStop) {
uint32_t timeToSleep = getSecondsToSleep();
esp_sleep_enable_timer_wakeup(timeToSleep * 1000000); // 1 min = 60sec
Serial.print("(Sleeping : "); Serial.print(timeToSleep); Serial.println("seconds)");
delay(100);
LoRa_Utils::wakeRadio();
esp_light_sleep_start();
}
}
}

View File

@@ -1,34 +1,110 @@
#include "station_utils.h"
#include "battery_utils.h"
#include "aprs_is_utils.h"
#include "configuration.h"
#include "lora_utils.h"
#include "display.h"
#include "utils.h"
#include <vector>
extern Configuration Config;
extern uint32_t lastRxTime;
extern String fourthLine;
extern bool shouldSleepLowVoltage;
uint32_t lastTxTime = millis();
std::vector<String> lastHeardStation;
std::vector<LastHeardStation> lastHeardStations;
std::vector<String> outputPacketBuffer;
std::vector<String> packet25SegBuffer;
std::vector<Packet25SegBuffer> packet25SegBuffer;
std::vector<String> blacklist;
std::vector<String> managers;
std::vector<LastHeardStation> lastHeardObjects;
bool saveNewDigiEcoModeConfig = false;
namespace STATION_Utils {
void deleteNotHeard() {
std::vector<String> lastHeardStation_temp;
for (int i = 0; i < lastHeardStation.size(); i++) {
String deltaTimeString = lastHeardStation[i].substring(lastHeardStation[i].indexOf(",") + 1);
uint32_t deltaTime = deltaTimeString.toInt();
if ((millis() - deltaTime) < Config.rememberStationTime * 60 * 1000) {
lastHeardStation_temp.push_back(lastHeardStation[i]);
std::vector<String> loadCallSignList(const String& list) {
std::vector<String> loadedList;
String callsigns = list;
callsigns.trim();
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
}
return loadedList;
}
void loadBlacklistAndManagers() {
blacklist = loadCallSignList(Config.blacklist);
managers = loadCallSignList(Config.remoteManagement.managers);
}
bool checkCallsignList(const std::vector<String>& list, const String& callsign) {
for (int 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;
} else {
if (list[i] == callsign) return true;
}
}
return false;
}
bool isBlacklisted(const String& callsign) {
return checkCallsignList(blacklist, callsign);
}
bool isManager(const String& callsign) {
return checkCallsignList(managers, callsign);
}
void cleanObjectsHeard() {
for (auto it = lastHeardObjects.begin(); it != lastHeardObjects.end(); ) {
if (millis() - it->lastHeardTime >= 9.75 * 60 * 1000) { // 9.75 = 9min 45secs
it = lastHeardObjects.erase(it); // erase() returns the next valid iterator
} else {
++it; // Only increment if not erasing
}
}
lastHeardStation.clear();
}
bool checkObjectTime(const String& packet) {
cleanObjectsHeard();
int objectIDIndex = packet.indexOf(":;");
String object = packet.substring(objectIDIndex + 2, objectIDIndex + 11);
object.trim();
for (int i = 0; i < lastHeardObjects.size(); i++) { // Check if i should Tx object
if (lastHeardObjects[i].station == object) return false;
}
lastHeardObjects.emplace_back(LastHeardStation{millis(), object}); // Add new object and Tx
return true;
}
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]);
}
}
lastHeardStations.clear();
for (int j = 0; j < lastHeardStation_temp.size(); j++) {
lastHeardStation.push_back(lastHeardStation_temp[j]);
lastHeardStations.push_back(lastHeardStation_temp[j]);
}
lastHeardStation_temp.clear();
}
@@ -36,79 +112,83 @@ namespace STATION_Utils {
void updateLastHeard(const String& station) {
deleteNotHeard();
bool stationHeard = false;
for (int i = 0; i < lastHeardStation.size(); i++) {
if (lastHeardStation[i].substring(0, lastHeardStation[i].indexOf(",")) == station) {
lastHeardStation[i] = station + "," + String(millis());
for (int i = 0; i < lastHeardStations.size(); i++) {
if (lastHeardStations[i].station == station) {
lastHeardStations[i].lastHeardTime = millis();
stationHeard = true;
break;
}
}
if (!stationHeard) {
lastHeardStation.push_back(station + "," + String(millis()));
}
fourthLine = "Stations (";
fourthLine += String(Config.rememberStationTime);
fourthLine += "min) = ";
if (lastHeardStation.size() < 10) {
fourthLine += " ";
}
fourthLine += String(lastHeardStation.size());
if (!stationHeard) lastHeardStations.emplace_back(LastHeardStation{millis(), station});
Utils::activeStations();
}
bool wasHeard(const String& station) {
deleteNotHeard();
for (int i = 0; i < lastHeardStation.size(); i++) {
if (lastHeardStation[i].substring(0, lastHeardStation[i].indexOf(",")) == station) {
for (int i = 0; i < lastHeardStations.size(); i++) {
if (lastHeardStations[i].station == station) {
Utils::println(" ---> Listened Station");
return true;
}
}
Utils::println(" ---> Station not Heard for last 30 min (Not Tx)\n");
Utils::println(" ---> Station not Heard in " + String(Config.rememberStationTime) + " min: No Tx");
return false;
}
void clean25SegBuffer() {
if (!packet25SegBuffer.empty()) {
String deltaTimeString = packet25SegBuffer[0].substring(0, packet25SegBuffer[0].indexOf(","));
uint32_t deltaTime = deltaTimeString.toInt();
if ((millis() - deltaTime) > 25 * 1000) {
packet25SegBuffer.erase(packet25SegBuffer.begin());
}
}
if (!packet25SegBuffer.empty() && (millis() - packet25SegBuffer[0].receivedTime) > 25 * 1000) packet25SegBuffer.erase(packet25SegBuffer.begin());
}
bool check25SegBuffer(const String& station, const String& textMessage) {
if (!packet25SegBuffer.empty()) {
bool shouldBeIgnored = false;
for (int i = 0; i < packet25SegBuffer.size(); i++) {
const String& temp = packet25SegBuffer[i].substring(packet25SegBuffer[i].indexOf(",") + 1);
const String& bufferStation = temp.substring(0, temp.indexOf(","));
const String& bufferMessage = temp.substring(temp.indexOf(",") + 1);
if (bufferStation == station && bufferMessage == textMessage) {
shouldBeIgnored = true;
}
if (packet25SegBuffer[i].station == station && packet25SegBuffer[i].payload == textMessage) return false;
}
if (shouldBeIgnored) {
return false;
} else {
packet25SegBuffer.push_back(String(millis()) + "," + station + "," + textMessage);
return true;
}
} else {
packet25SegBuffer.push_back(String(millis()) + "," + station + "," + textMessage);
return true;
}
}
packet25SegBuffer.emplace_back(Packet25SegBuffer{millis(), station, textMessage});
return true;
}
void processOutputPacketBufferUltraEcoMode() {
size_t currentIndex = 0;
while (currentIndex < outputPacketBuffer.size()) { // this sends all packets from output buffer
delay(3000); // and cleans buffer to avoid sending packets with time offset
LoRa_Utils::sendNewPacket(outputPacketBuffer[currentIndex]); // next time it wakes up
currentIndex++;
}
outputPacketBuffer.clear();
//
if (saveNewDigiEcoModeConfig) {
Config.writeFile();
delay(1000);
displayToggle(false);
ESP.restart();
}
//
}
void processOutputPacketBuffer() {
int timeToWait = 3 * 1000; // 3 segs between packet Tx and also Rx ???
uint32_t lastRx = millis() - lastRxTime;
uint32_t lastTx = millis() - lastTxTime;
int timeToWait = 3 * 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) {
LoRa_Utils::sendNewPacket(outputPacketBuffer[0]);
outputPacketBuffer.erase(outputPacketBuffer.begin());
lastTxTime = millis();
}
if (shouldSleepLowVoltage) {
while (outputPacketBuffer.size() > 0) {
LoRa_Utils::sendNewPacket(outputPacketBuffer[0]);
outputPacketBuffer.erase(outputPacketBuffer.begin());
delay(4000);
}
}
if (saveNewDigiEcoModeConfig) {
Config.writeFile();
delay(1000);
displayToggle(false);
ESP.restart();
}
}
void addToOutputPacketBuffer(const String& packet) {

View File

@@ -1,19 +0,0 @@
#ifndef STATION_UTILS_H_
#define STATION_UTILS_H_
#include <Arduino.h>
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);
void processOutputPacketBuffer();
void addToOutputPacketBuffer(const String& packet);
}
#endif

View File

@@ -4,6 +4,7 @@
#include "syslog_utils.h"
#include "gps_utils.h"
extern Configuration Config;
WiFiUDP udpClient;
@@ -20,6 +21,10 @@ 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(">"));
switch (type) {
case 0: // CRC
syslogPacket.concat("CRC / CRC-ERROR / ");
@@ -28,59 +33,57 @@ namespace SYSLOG_Utils {
break;
case 1: // RX
syslogPacket.concat("RX / ");
if (packet.indexOf("::") > 10) {
if (nextChar == ':') {
syslogPacket.concat("MESSAGE / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(" ---> "); syslogPacket.concat(packet.substring(packet.indexOf("::") + 2));
syslogPacket.concat(signalData);
} else if (packet.indexOf(":!") > 10 || packet.indexOf(":=") > 10) {
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
syslogPacket.concat("GPS / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(sender);
syslogPacket.concat(" / ");
int greaterThanIndex = packet.indexOf(">");
if (packet.indexOf("WIDE1-1") > 10) {
syslogPacket.concat(packet.substring(packet.indexOf(">") + 1, packet.indexOf(",")));
syslogPacket.concat(packet.substring(greaterThanIndex + 1, packet.indexOf(",")));
syslogPacket.concat(" / WIDE1-1");
} else {
syslogPacket.concat(packet.substring(packet.indexOf(">") + 1, packet.indexOf(":")));
syslogPacket.concat(packet.substring(greaterThanIndex + 1, colonIndex));
syslogPacket.concat(" / -");
}
syslogPacket.concat(signalData);
syslogPacket.concat(" / ");
syslogPacket.concat(GPS_Utils::getDistanceAndComment(packet));
} else if (packet.indexOf(":>") > 10) {
} else if (nextChar == '>') {
syslogPacket.concat("STATUS / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf(":>") + 2));
syslogPacket.concat(signalData);
} else if (packet.indexOf(":`") > 10) {
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (nextChar == '`') {
syslogPacket.concat("MIC-E / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf(":`") + 2));
syslogPacket.concat(signalData);
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (nextChar == ';') {
syslogPacket.concat("OBJECT / ");
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(colonIndex + 2));
} else if (packet.indexOf(":T#") >= 10 && packet.indexOf(":=/") == -1) {
syslogPacket.concat("TELEMETRY / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf(":T#") + 3));
syslogPacket.concat(signalData);
} else if (packet.indexOf(":;") > 10) {
syslogPacket.concat("OBJECT / ");
syslogPacket.concat(packet.substring(3, packet.indexOf(">")));
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf(":;") + 2));
syslogPacket.concat(signalData);
} else {
syslogPacket.concat(packet);
syslogPacket.concat(signalData);
}
syslogPacket.concat(signalData);
if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
syslogPacket.concat(" / ");
syslogPacket.concat(GPS_Utils::getDistanceAndComment(packet));
}
break;
case 2: // APRSIS TX
syslogPacket.concat("APRSIS TX / ");
if (packet.indexOf(":>") > 10) {
if (nextChar == '>') {
syslogPacket.concat("StartUp_Status / ");
syslogPacket.concat(packet.substring(packet.indexOf(":>") + 2));
syslogPacket.concat(packet.substring(colonIndex + 2));
} else {
syslogPacket.concat("QUERY / ");
syslogPacket.concat(packet);
@@ -91,11 +94,11 @@ namespace SYSLOG_Utils {
if (packet.indexOf("RFONLY") > 10) {
syslogPacket.concat("RFONLY / ");
syslogPacket.concat(packet);
} else if (packet.indexOf("::") > 10) {
} else if (nextChar == ':') {
syslogPacket.concat("MESSAGE / ");
syslogPacket.concat(packet.substring(0,packet.indexOf(">")));
syslogPacket.concat(sender);
syslogPacket.concat(" ---> ");
syslogPacket.concat(packet.substring(packet.indexOf("::") + 2));
syslogPacket.concat(packet.substring(colonIndex + 2));
} else {
syslogPacket.concat(packet);
}

View File

@@ -5,6 +5,7 @@
#include "station_utils.h"
#include "utils.h"
extern Configuration Config;
#define MAX_CLIENTS 4
@@ -19,17 +20,18 @@ WiFiServer tncServer(TNC_PORT);
String inputServerBuffer[INPUT_BUFFER_SIZE];
String inputSerialBuffer = "";
namespace TNC_Utils {
void setup() {
if (Config.tnc.enableServer) {
if (Config.tnc.enableServer && Config.digi.ecoMode == 0) {
tncServer.stop();
tncServer.begin();
}
}
void checkNewClients() {
WiFiClient new_client = tncServer.available();
WiFiClient new_client = tncServer.accept();
if (new_client.connected()) {
for (int i = 0; i < MAX_CLIENTS; i++) {
WiFiClient* client = clients[i];
@@ -43,16 +45,9 @@ namespace TNC_Utils {
}
void handleInputData(char character, int bufferIndex) {
String* data;
if (bufferIndex == -1) {
data = &inputSerialBuffer;
} else {
data = &inputServerBuffer[bufferIndex];
}
if (data->length() == 0 && character != (char)FEND) {
return;
}
String* data = (bufferIndex == -1) ? &inputSerialBuffer : &inputServerBuffer[bufferIndex];
if (data->length() == 0 && character != (char)FEND) return;
data->concat(character);
if (character == (char)FEND && data->length() > 3) {
@@ -133,12 +128,14 @@ namespace TNC_Utils {
}
void loop() {
if (Config.tnc.enableServer) {
checkNewClients();
readFromClients();
}
if (Config.tnc.enableSerial) {
readFromSerial();
if (Config.digi.ecoMode == 0) {
if (Config.tnc.enableServer) {
checkNewClients();
readFromClients();
}
if (Config.tnc.enableSerial) {
readFromSerial();
}
}
}
}

View File

@@ -1,20 +1,23 @@
#include <TinyGPS++.h>
#include <WiFi.h>
#include "configuration.h"
#include "station_utils.h"
#include "battery_utils.h"
#include "aprs_is_utils.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "syslog_utils.h"
#include "A7670_utils.h"
#include "lora_utils.h"
#include "wifi_utils.h"
#include "gps_utils.h"
#include "bme_utils.h"
#include "wx_utils.h"
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern WiFiClient espClient;
extern TinyGPSPlus gps;
extern String versionDate;
extern String firstLine;
extern String secondLine;
@@ -25,7 +28,6 @@ extern String sixthLine;
extern String seventhLine;
extern String iGateBeaconPacket;
extern String iGateLoRaBeaconPacket;
extern std::vector<String> lastHeardStation;
extern int rssi;
extern float snr;
extern int freqError;
@@ -35,11 +37,17 @@ extern int wxModuleType;
extern bool backUpDigiMode;
extern bool shouldSleepLowVoltage;
extern bool transmitFlag;
extern bool passcodeValid;
extern std::vector<LastHeardStation> lastHeardStations;
bool statusAfterBoot = true;
bool beaconUpdate = true;
bool sendStartTelemetry = true;
bool beaconUpdate = false;
uint32_t lastBeaconTx = 0;
uint32_t lastScreenOn = millis();
String beaconPacket;
String secondaryBeaconPacket;
namespace Utils {
@@ -60,7 +68,6 @@ namespace Utils {
statusAfterBoot = false;
}
if (statusAfterBoot && !Config.beacon.sendViaAPRSIS && Config.beacon.sendViaRF) {
delay(2000);
status.concat(":>https://github.com/richonguzman/LoRa_APRS_iGate ");
status.concat(versionDate);
STATION_Utils::addToOutputPacketBuffer(status);
@@ -69,22 +76,32 @@ namespace Utils {
}
String getLocalIP() {
if (!WiFiConnected) {
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) {
return "- BACKUP DIGI MODE -";
} else {
return "IP : " + String(WiFi.localIP()[0]) + "." + String(WiFi.localIP()[1]) + "." + String(WiFi.localIP()[2]) + "." + String(WiFi.localIP()[3]);
}
}
}
void setupDisplay() {
setup_display();
if (Config.digi.ecoMode != 1) displaySetup();
#ifdef INTERNAL_LED_PIN
digitalWrite(INTERNAL_LED_PIN,HIGH);
#endif
Serial.println("\nStarting Station: " + Config.callsign + " Version: " + versionDate);
show_display(" LoRa APRS", "", " ( iGATE & DIGI )", "", "", "Richonguzman / CA2RXU", " " + versionDate, 4000);
Serial.print("(DigiEcoMode: ");
if (Config.digi.ecoMode == 0) {
Serial.println("OFF)");
} else if (Config.digi.ecoMode == 1) {
Serial.println("ON)");
} else {
Serial.println("ON / Only Serial Output)");
}
displayShow(" LoRa APRS", "", "", " ( iGATE & DIGI )", "", "" , " CA2RXU " + versionDate, 4000);
#ifdef INTERNAL_LED_PIN
digitalWrite(INTERNAL_LED_PIN,LOW);
#endif
@@ -93,13 +110,80 @@ namespace Utils {
}
void activeStations() {
fourthLine = "Stations (";
fourthLine.concat(String(Config.rememberStationTime));
fourthLine.concat("min) = ");
if (lastHeardStation.size() < 10) {
fourthLine += " ";
char buffer[30]; // Adjust size as needed
sprintf(buffer, "Stations (%dmin) = %2d", Config.rememberStationTime, lastHeardStations.size());
fourthLine = buffer;
}
void sendInitialTelemetryPackets() {
char sender[10]; // 9 characters + null terminator
snprintf(sender, sizeof(sender), "%-9s", Config.callsign.c_str()); // Left-align with spaces
String baseAPRSISTelemetryPacket = Config.callsign;
baseAPRSISTelemetryPacket += ">APLRG1,TCPIP,qAC::";
baseAPRSISTelemetryPacket += sender;
baseAPRSISTelemetryPacket += ":";
String baseRFTelemetryPacket = Config.callsign;
baseRFTelemetryPacket += ">APLRG1";
if (Config.beacon.path.indexOf("WIDE") != -1) {
baseRFTelemetryPacket += ",";
baseRFTelemetryPacket += Config.beacon.path;
}
fourthLine.concat(String(lastHeardStation.size()));
baseRFTelemetryPacket += "::";
baseRFTelemetryPacket += sender;
baseRFTelemetryPacket += ":";
String telemetryPacket1 = "EQNS.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket1 += "0,0.01,0";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket1 += String(Config.battery.sendInternalVoltage ? ",0,0.02,0" : "0,0.02,0");
}
String telemetryPacket2 = "UNIT.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket2 += "VDC";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket2 += String(Config.battery.sendInternalVoltage ? ",VDC" : "VDC");
}
String telemetryPacket3 = "PARM.";
if (Config.battery.sendInternalVoltage) {
telemetryPacket3 += "V_Batt";
}
if (Config.battery.sendExternalVoltage) {
telemetryPacket3 += String(Config.battery.sendInternalVoltage ? ",V_Ext" : "V_Ext");
}
if (Config.beacon.sendViaAPRSIS) {
#ifdef HAS_A7670
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket1);
delay(300);
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket2);
delay(300);
A7670_Utils::uploadToAPRSIS(baseAPRSISTelemetryPacket + telemetryPacket3);
delay(300);
#else
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket1);
delay(300);
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket2);
delay(300);
APRS_IS_Utils::upload(baseAPRSISTelemetryPacket + telemetryPacket3);
delay(300);
#endif
delay(300);
} else if (Config.beacon.sendViaRF) {
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket1);
delay(3000);
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket2);
delay(3000);
LoRa_Utils::sendNewPacket(baseRFTelemetryPacket + telemetryPacket3);
delay(3000);
}
sendStartTelemetry = false;
}
void checkBeaconInterval() {
@@ -108,25 +192,46 @@ namespace Utils {
beaconUpdate = true;
}
if (beaconUpdate) {
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
display_toggle(true);
#ifdef HAS_GPS
if (Config.beacon.gpsActive && gps.location.lat() == 0.0 && gps.location.lng() == 0.0 && Config.beacon.latitude == 0.0 && Config.beacon.longitude == 0.0) {
GPS_Utils::getData();
beaconUpdate = false;
}
#endif
if (beaconUpdate) {
if (!Config.display.alwaysOn && Config.display.timeout != 0) displayToggle(true);
if (sendStartTelemetry &&
Config.battery.sendVoltageAsTelemetry &&
!Config.wxsensor.active &&
(Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage) &&
(lastBeaconTx > 0)) {
sendInitialTelemetryPackets();
}
Utils::println("-- Sending Beacon to APRSIS --");
STATION_Utils::deleteNotHeard();
activeStations();
String beaconPacket = iGateBeaconPacket;
String secondaryBeaconPacket = iGateLoRaBeaconPacket;
if (Config.bme.active && wxModuleType != 0) {
String sensorData = BME_Utils::readDataSensor();
beaconPacket += sensorData;
secondaryBeaconPacket += sensorData;
} else if (Config.bme.active && wxModuleType == 0) {
beaconPacket += ".../...g...t...r...p...P...h..b.....";
secondaryBeaconPacket += ".../...g...t...r...p...P...h..b.....";
beaconPacket = iGateBeaconPacket;
secondaryBeaconPacket = iGateLoRaBeaconPacket;
#ifdef HAS_GPS
if (Config.beacon.gpsActive && Config.digi.ecoMode == 0) {
GPS_Utils::getData();
if (gps.location.isUpdated() && gps.location.lat() != 0.0 && gps.location.lng() != 0.0) {
GPS_Utils::generateBeaconFirstPart();
String encodedGPS = GPS_Utils::encodeGPS(gps.location.lat(), gps.location.lng(), Config.beacon.overlay, Config.beacon.symbol);
beaconPacket = iGateBeaconPacket + encodedGPS;
secondaryBeaconPacket = iGateLoRaBeaconPacket + encodedGPS;
}
}
#endif
if (Config.wxsensor.active) {
const char* sensorData = (wxModuleType == 0) ? ".../...g...t..." : WX_Utils::readDataSensor().c_str();
beaconPacket += sensorData;
secondaryBeaconPacket += sensorData;
}
beaconPacket += Config.beacon.comment;
secondaryBeaconPacket += Config.beacon.comment;
@@ -134,45 +239,66 @@ namespace Utils {
#if defined(BATTERY_PIN) || defined(HAS_AXP192) || defined(HAS_AXP2101)
if (Config.battery.sendInternalVoltage || Config.battery.monitorInternalVoltage) {
float internalVoltage = BATTERY_Utils::checkInternalVoltage();
String internalVoltageInfo = String(internalVoltage,2) + "V";
if (Config.battery.sendInternalVoltage) {
beaconPacket += " Batt=";
beaconPacket += internalVoltageInfo;
secondaryBeaconPacket += " Batt=";
secondaryBeaconPacket += internalVoltageInfo;
sixthLine = " (Batt=";
sixthLine += internalVoltageInfo;
sixthLine += ")";
}
if (Config.battery.monitorInternalVoltage && internalVoltage < Config.battery.internalSleepVoltage) {
beaconPacket += " **IntBatWarning:SLEEP**";
secondaryBeaconPacket += " **IntBatWarning:SLEEP**";
shouldSleepLowVoltage = true;
}
}
if (Config.battery.sendInternalVoltage) {
char internalVoltageInfo[10]; // Enough to hold "xx.xxV\0"
snprintf(internalVoltageInfo, sizeof(internalVoltageInfo), "%.2fV", internalVoltage);
char sixthLineBuffer[25]; // Enough to hold " (Batt=xx.xxV)"
snprintf(sixthLineBuffer, sizeof(sixthLineBuffer), " (Batt=%s)", internalVoltageInfo);
sixthLine = sixthLineBuffer;
if (!Config.battery.sendVoltageAsTelemetry) {
beaconPacket += " Batt=";
beaconPacket += internalVoltageInfo;
secondaryBeaconPacket += " Batt=";
secondaryBeaconPacket += internalVoltageInfo;
}
}
}
#endif
if (Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) {
float externalVoltage = BATTERY_Utils::checkExternalVoltage();
String externalVoltageInfo = String(externalVoltage,2) + "V";
if (Config.battery.sendExternalVoltage) {
beaconPacket += " Ext=";
beaconPacket += externalVoltageInfo;
secondaryBeaconPacket += " Ext=";
secondaryBeaconPacket += externalVoltageInfo;
sixthLine = " (Ext V=";
sixthLine += externalVoltageInfo;
sixthLine += ")";
}
if (Config.battery.monitorExternalVoltage && externalVoltage < Config.battery.externalSleepVoltage) {
beaconPacket += " **ExtBatWarning:SLEEP**";
secondaryBeaconPacket += " **ExtBatWarning:SLEEP**";
shouldSleepLowVoltage = true;
#ifndef HELTEC_WP
if (Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) {
float externalVoltage = BATTERY_Utils::checkExternalVoltage();
if (Config.battery.monitorExternalVoltage && externalVoltage < Config.battery.externalSleepVoltage) {
beaconPacket += " **ExtBatWarning:SLEEP**";
secondaryBeaconPacket += " **ExtBatWarning:SLEEP**";
shouldSleepLowVoltage = true;
}
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;
if (!Config.battery.sendVoltageAsTelemetry) {
beaconPacket += " Ext=";
beaconPacket += externalVoltageInfo;
secondaryBeaconPacket += " Ext=";
secondaryBeaconPacket += externalVoltageInfo;
}
}
}
#endif
if (Config.battery.sendVoltageAsTelemetry && !Config.wxsensor.active && (Config.battery.sendInternalVoltage || Config.battery.sendExternalVoltage)){
String encodedTelemetry = BATTERY_Utils::generateEncodedTelemetry();
beaconPacket += encodedTelemetry;
secondaryBeaconPacket += encodedTelemetry;
}
if (Config.aprs_is.active && Config.beacon.sendViaAPRSIS && !backUpDigiMode) {
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING IGATE BEACON", 0);
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...";
#ifdef HAS_A7670
A7670_Utils::uploadToAPRSIS(beaconPacket);
@@ -182,7 +308,8 @@ namespace Utils {
}
if (Config.beacon.sendViaRF || backUpDigiMode) {
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING DIGI BEACON", 0);
Utils::println("-- Sending Beacon to RF --");
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, "SENDING DIGI BEACON", 0);
seventhLine = " listening...";
STATION_Utils::addToOutputPacketBuffer(secondaryBeaconPacket);
}
@@ -200,14 +327,14 @@ namespace Utils {
void checkDisplayInterval() {
uint32_t lastDisplayTime = millis() - lastScreenOn;
if (!Config.display.alwaysOn && lastDisplayTime >= Config.display.timeout * 1000) {
display_toggle(false);
displayToggle(false);
}
}
void validateFreqs() {
if (Config.loramodule.txFreq != Config.loramodule.rxFreq && abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) < 125000) {
Serial.println("Tx Freq less than 125kHz from Rx Freq ---> NOT VALID");
show_display("Tx Freq is less than ", "125kHz from Rx Freq", "device will autofix", "and then reboot", 1000);
displayShow("Tx Freq is less than ", "125kHz from Rx Freq", "device will autofix", "and then reboot", 1000);
Config.loramodule.txFreq = Config.loramodule.rxFreq; // Inform about that but then change the TX QRG to RX QRG and reset the device
Config.writeFile();
ESP.restart();
@@ -223,57 +350,49 @@ namespace Utils {
case 1: // APRS-LoRa
fifthLine = "APRS-IS ----> LoRa Tx";
break;
case 2: // Digi
case 2: // Digipeater
fifthLine = "LoRa Rx ----> LoRa Tx";
break;
}
int firstColonIndex = packet.indexOf(":");
char nextChar = packet[firstColonIndex + 1];
for (int i = sender.length(); i < 9; i++) {
sender += " ";
}
sixthLine = sender;
String seventhLineHelper = "RSSI:";
seventhLineHelper += String(rssi);
seventhLineHelper += "dBm SNR: ";
seventhLineHelper += String(snr);
seventhLineHelper += "dBm";
if (packet.indexOf("::") >= 10) {
if (nextChar == ':') {
sixthLine += "> MESSAGE";
seventhLine = seventhLineHelper;
} else if (packet.indexOf(":>") >= 10) {
} else if (nextChar == '>') {
sixthLine += "> NEW STATUS";
seventhLine = seventhLineHelper;
} else if (packet.indexOf(":!") >= 10 || packet.indexOf(":=") >= 10) {
} else if (nextChar == '!' || nextChar == '=' || nextChar == '@') {
sixthLine += "> GPS BEACON";
if (!Config.syslog.active) {
GPS_Utils::getDistanceAndComment(packet); // to be checked!!!
}
if (!Config.syslog.active) GPS_Utils::getDistanceAndComment(packet); // to be checked!!!
seventhLine = "RSSI:";
seventhLine += String(rssi);
seventhLine += "dBm";
if (rssi <= -100) {
seventhLine += " ";
} else {
seventhLine += " ";
}
if (distance.indexOf(".") == 1) {
seventhLine += " ";
}
seventhLine += (rssi <= -100) ? " " : " ";
if (distance.indexOf(".") == 1) seventhLine += " ";
seventhLine += "D:";
seventhLine += distance;
seventhLine += "km";
} else if (nextChar == '`' || nextChar == '\'') {
sixthLine += "> MIC-E";
} else if (nextChar == ';') {
sixthLine += "> OBJECT";
} else if (packet.indexOf(":T#") >= 10 && packet.indexOf(":=/") == -1) {
sixthLine += "> TELEMETRY";
seventhLine = seventhLineHelper;
} else if (packet.indexOf(":`") >= 10) {
sixthLine += "> MIC-E";
seventhLine = seventhLineHelper;
} else if (packet.indexOf(":;") >= 10) {
sixthLine += "> OBJECT";
seventhLine = seventhLineHelper;
} else {
sixthLine += "> ??????????";
seventhLine = seventhLineHelper;
}
if (nextChar != '!' && nextChar != '=' && nextChar != '@') { // Common assignment for non-GPS cases
seventhLine = "RSSI:";
seventhLine += String(rssi);
seventhLine += "dBm SNR: ";
seventhLine += String(snr);
seventhLine += "dBm";
}
}
@@ -306,13 +425,13 @@ namespace Utils {
void checkSleepByLowBatteryVoltage(uint8_t mode) {
if (shouldSleepLowVoltage) {
if (mode == 0) {
if (mode == 0) { // at startup
delay(3000);
}
Serial.println("\n\n*** Sleeping Low Battey Voltage ***\n\n");
esp_sleep_enable_timer_wakeup(30 * 60 * 1000000); // sleep 30 min
if (mode == 1) {
display_toggle(false);
if (mode == 1) { // low voltage detected after a while
displayToggle(false);
}
#ifdef VEXT_CTRL
#ifndef HELTEC_WSL_V3
@@ -330,7 +449,7 @@ namespace Utils {
if (callsign == "WLNK-1") return true;
String cleanCallsign;
if (callsign.indexOf("-")) { // SSID Validation
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;
@@ -347,22 +466,25 @@ namespace Utils {
cleanCallsign = " " + cleanCallsign; // A0AA --> _A0AA
}
if (!isDigit(cleanCallsign[2]) || !isAlpha(cleanCallsign[3])) return false; // __0A must be validated
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) {
if (cleanCallsign.length() > 4) { // to validate ____AA
for (int i = 5; i <= cleanCallsign.length(); i++) {
if (!isAlpha(cleanCallsign[i - 1])) return false;
}
}
return true;
}

View File

@@ -5,6 +5,7 @@
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern uint32_t lastBeaconTx;
extern std::vector<ReceivedPacket> receivedPackets;
@@ -29,6 +30,11 @@ extern const char web_bootstrap_js[] asm("_binary_data_embed_bootstrap_js_gz_sta
extern const char web_bootstrap_js_end[] asm("_binary_data_embed_bootstrap_js_gz_end");
extern const size_t web_bootstrap_js_len = web_bootstrap_js_end - web_bootstrap_js;
// Declare external symbols for the embedded image data
extern const unsigned char favicon_data[] asm("_binary_data_embed_favicon_png_gz_start");
extern const unsigned char favicon_data_end[] asm("_binary_data_embed_favicon_png_gz_end");
extern const size_t favicon_data_len = favicon_data_end - favicon_data;
namespace WEB_Utils {
@@ -45,12 +51,24 @@ namespace WEB_Utils {
}
void handleHome(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", (const uint8_t*)web_index_html, web_index_html_len);
if(Config.webadmin.active && !request->authenticate(Config.webadmin.username.c_str(), Config.webadmin.password.c_str()))
return request->requestAuthentication();
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", (const uint8_t*)web_index_html, web_index_html_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
void handleFavicon(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse(200, "image/x-icon", (const uint8_t*)favicon_data, favicon_data_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
void handleReadConfiguration(AsyncWebServerRequest *request) {
if(Config.webadmin.active && !request->authenticate(Config.webadmin.username.c_str(), Config.webadmin.password.c_str()))
return request->requestAuthentication();
File file = SPIFFS.open("/igate_conf.json");
String fileContent;
@@ -65,10 +83,10 @@ namespace WEB_Utils {
StaticJsonDocument<1536> data;
for (int i = 0; i < receivedPackets.size(); i++) {
data[i]["millis"] = receivedPackets[i].millis;
data[i]["packet"] = receivedPackets[i].packet;
data[i]["RSSI"] = receivedPackets[i].RSSI;
data[i]["SNR"] = receivedPackets[i].SNR;
data[i]["rxTime"] = receivedPackets[i].rxTime;
data[i]["packet"] = receivedPackets[i].packet;
data[i]["RSSI"] = receivedPackets[i].RSSI;
data[i]["SNR"] = receivedPackets[i].SNR;
}
String buffer;
@@ -94,10 +112,10 @@ namespace WEB_Utils {
}
Config.callsign = request->getParam("callsign", true)->value();
Config.wifiAutoAP.password = request->getParam("wifi.autoAP.password", true)->value();
Config.wifiAutoAP.powerOff = request->getParam("wifi.autoAP.powerOff", true)->value().toInt();
Config.wifiAutoAP.password = request->getParam("wifi.autoAP.password", true)->value();
Config.wifiAutoAP.timeout = request->getParam("wifi.autoAP.timeout", true)->value().toInt();
Config.aprs_is.active = request->hasParam("aprs_is.active", true);
Config.aprs_is.passcode = request->getParam("aprs_is.passcode", true)->value();
@@ -118,8 +136,12 @@ namespace WEB_Utils {
Config.beacon.symbol = request->getParam("beacon.symbol", true)->value();
Config.beacon.path = request->getParam("beacon.path", true)->value();
Config.beacon.gpsActive = request->hasParam("beacon.gpsActive", true);
Config.beacon.gpsAmbiguity = request->hasParam("beacon.gpsAmbiguity", true);
Config.digi.mode = request->getParam("digi.mode", true)->value().toInt();
Config.digi.mode = request->getParam("digi.mode", true)->value().toInt();
Config.digi.ecoMode = request->getParam("digi.ecoMode", true)->value().toInt();;
Config.loramodule.txFreq = request->getParam("lora.txFreq", true)->value().toInt();
@@ -132,68 +154,77 @@ namespace WEB_Utils {
Config.loramodule.rxActive = request->hasParam("lora.rxActive", true);
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
Config.display.alwaysOn = request->hasParam("display.alwaysOn", true);
if (!Config.display.alwaysOn) {
Config.display.timeout = request->getParam("display.timeout", true)->value().toInt();
}
Config.display.turn180 = request->hasParam("display.turn180", true);
Config.display.turn180 = request->hasParam("display.turn180", true);
Config.battery.sendInternalVoltage = request->hasParam("battery.sendInternalVoltage", true);
Config.battery.monitorInternalVoltage = request->hasParam("battery.monitorInternalVoltage", true);
Config.battery.internalSleepVoltage = request->getParam("battery.internalSleepVoltage", true)->value().toFloat();
Config.battery.internalSleepVoltage = request->getParam("battery.internalSleepVoltage", true)->value().toFloat();
Config.battery.sendExternalVoltage = request->hasParam("battery.sendExternalVoltage", true);
if (Config.battery.sendExternalVoltage) {
Config.battery.externalVoltagePin = request->getParam("battery.externalVoltagePin", true)->value().toInt();
Config.battery.voltageDividerR1 = request->getParam("battery.voltageDividerR1", true)->value().toFloat();
Config.battery.voltageDividerR2 = request->getParam("battery.voltageDividerR2", true)->value().toFloat();
}
Config.battery.monitorExternalVoltage = request->hasParam("battery.monitorExternalVoltage", true);
Config.battery.externalSleepVoltage = request->getParam("battery.externalSleepVoltage", true)->value().toFloat();
Config.battery.externalSleepVoltage = request->getParam("battery.externalSleepVoltage", true)->value().toFloat();
Config.bme.active = request->hasParam("bme.active", true);
Config.bme.heightCorrection = request->getParam("bme.heightCorrection", true)->value().toInt();
Config.bme.temperatureCorrection = request->getParam("bme.temperatureCorrection", true)->value().toFloat();
if (Config.bme.active) {
Config.battery.sendVoltageAsTelemetry = request->hasParam("battery.sendVoltageAsTelemetry", true);
Config.wxsensor.active = request->hasParam("wxsensor.active", true);
Config.wxsensor.heightCorrection = request->getParam("wxsensor.heightCorrection", true)->value().toInt();
Config.wxsensor.temperatureCorrection = request->getParam("wxsensor.temperatureCorrection", true)->value().toFloat();
if (Config.wxsensor.active) {
Config.beacon.symbol = "_";
}
Config.syslog.active = request->hasParam("syslog.active", true);
if (Config.syslog.active) {
Config.syslog.server = request->getParam("syslog.server", true)->value();
Config.syslog.port = request->getParam("syslog.port", true)->value().toInt();
Config.syslog.server = request->getParam("syslog.server", true)->value();
Config.syslog.port = request->getParam("syslog.port", true)->value().toInt();
}
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.enableServer = request->hasParam("tnc.enableServer", true);
Config.tnc.enableSerial = request->hasParam("tnc.enableSerial", true);
Config.tnc.acceptOwn = request->hasParam("tnc.acceptOwn", true);
Config.rebootMode = request->hasParam("other.rebootMode", true);
Config.rebootModeTime = request->getParam("other.rebootModeTime", true)->value().toInt();
Config.ota.username = request->getParam("ota.username", true)->value();
Config.ota.password = request->getParam("ota.password", true)->value();
Config.rememberStationTime = request->getParam("other.rememberStationTime", true)->value().toInt();
Config.rememberStationTime = request->getParam("other.rememberStationTime", true)->value().toInt();
Config.backupDigiMode = request->hasParam("other.backupDigiMode", true);
Config.personalNote = request->getParam("personalNote", true)->value();
Config.lowPowerMode = request->hasParam("other.lowPowerMode", true);
Config.lowVoltageCutOff = request->getParam("other.lowVoltageCutOff", true)->value().toDouble();
Config.blacklist = request->getParam("blacklist", true)->value();
Config.webadmin.active = request->hasParam("webadmin.active", true);
if (Config.webadmin.active) {
Config.webadmin.username = request->getParam("webadmin.username", true)->value();
Config.webadmin.password = request->getParam("webadmin.password", true)->value();
}
Config.ntp.gmtCorrection = request->getParam("ntp.gmtCorrection", true)->value().toFloat();
Config.remoteManagement.managers = request->getParam("remoteManagement.managers", true)->value();
Config.remoteManagement.rfOnly = request->getParam("remoteManagement.rfOnly", true);
Config.writeFile();
AsyncWebServerResponse *response = request->beginResponse(302, "text/html", "");
response->addHeader("Location", "/");
request->send(response);
display_toggle(false);
displayToggle(false);
delay(200);
ESP.restart();
}
@@ -205,7 +236,7 @@ namespace WEB_Utils {
request->send(200, "text/plain", "Beacon will be sent in a while");
} else if (type == "reboot") {
display_toggle(false);
displayToggle(false);
ESP.restart();
} else {
request->send(404, "text/plain", "Not Found");
@@ -213,48 +244,51 @@ namespace WEB_Utils {
}
void handleStyle(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/css", (const uint8_t*)web_style_css, web_style_css_len);
AsyncWebServerResponse *response = request->beginResponse(200, "text/css", (const uint8_t*)web_style_css, web_style_css_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
void handleScript(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/javascript", (const uint8_t*)web_script_js, web_script_js_len);
AsyncWebServerResponse *response = request->beginResponse(200, "text/javascript", (const uint8_t*)web_script_js, web_script_js_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
void handleBootstrapStyle(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/css", (const uint8_t*)web_bootstrap_css, web_bootstrap_css_len);
AsyncWebServerResponse *response = request->beginResponse(200, "text/css", (const uint8_t*)web_bootstrap_css, web_bootstrap_css_len);
response->addHeader("Content-Encoding", "gzip");
response->addHeader("Cache-Control", "max-age=3600");
request->send(response);
}
void handleBootstrapScript(AsyncWebServerRequest *request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/javascript", (const uint8_t*)web_bootstrap_js, web_bootstrap_js_len);
AsyncWebServerResponse *response = request->beginResponse(200, "text/javascript", (const uint8_t*)web_bootstrap_js, web_bootstrap_js_len);
response->addHeader("Content-Encoding", "gzip");
response->addHeader("Cache-Control", "max-age=3600");
request->send(response);
}
void setup() {
server.on("/", HTTP_GET, handleHome);
server.on("/status", HTTP_GET, handleStatus);
server.on("/received-packets.json", HTTP_GET, handleReceivedPackets);
server.on("/configuration.json", HTTP_GET, handleReadConfiguration);
server.on("/configuration.json", HTTP_POST, handleWriteConfiguration);
server.on("/action", HTTP_POST, handleAction);
server.on("/style.css", HTTP_GET, handleStyle);
server.on("/script.js", HTTP_GET, handleScript);
server.on("/bootstrap.css", HTTP_GET, handleBootstrapStyle);
server.on("/bootstrap.js", HTTP_GET, handleBootstrapScript);
if (Config.digi.ecoMode == 0) {
server.on("/", HTTP_GET, handleHome);
server.on("/status", HTTP_GET, handleStatus);
server.on("/received-packets.json", HTTP_GET, handleReceivedPackets);
server.on("/configuration.json", HTTP_GET, handleReadConfiguration);
server.on("/configuration.json", HTTP_POST, handleWriteConfiguration);
server.on("/action", HTTP_POST, handleAction);
server.on("/style.css", HTTP_GET, handleStyle);
server.on("/script.js", HTTP_GET, handleScript);
server.on("/bootstrap.css", HTTP_GET, handleBootstrapStyle);
server.on("/bootstrap.js", HTTP_GET, handleBootstrapScript);
server.on("/favicon.png", HTTP_GET, handleFavicon);
OTA_Utils::setup(&server); // Include OTA Updater for WebServer
OTA_Utils::setup(&server); // Include OTA Updater for WebServer
server.onNotFound(handleNotFound);
server.onNotFound(handleNotFound);
server.begin();
server.begin();
}
}
}

View File

@@ -1,10 +1,11 @@
#include <WiFi.h>
#include "configuration.h"
#include "boards_pinout.h"
#include "board_pinout.h"
#include "wifi_utils.h"
#include "display.h"
#include "utils.h"
extern Configuration Config;
extern uint8_t myWiFiAPIndex;
@@ -23,33 +24,35 @@ uint32_t lastBackupDigiTime = millis();
namespace WIFI_Utils {
void checkWiFi() {
if (backUpDigiMode) {
uint32_t WiFiCheck = millis() - lastBackupDigiTime;
if (WiFi.status() != WL_CONNECTED && WiFiCheck >= 15 * 60 * 1000) {
Serial.println("*** Stoping BackUp Digi Mode ***");
backUpDigiMode = false;
wifiCounter = 0;
} else if (WiFi.status() == WL_CONNECTED) {
Serial.println("*** WiFi Reconnect Success (Stoping Backup Digi Mode) ***");
backUpDigiMode = false;
wifiCounter = 0;
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 (!backUpDigiMode && (WiFi.status() != WL_CONNECTED) && ((millis() - previousWiFiMillis) >= 30 * 1000) && !WiFiAutoAPStarted) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
previousWiFiMillis = millis();
if (!backUpDigiMode && (WiFi.status() != WL_CONNECTED) && ((millis() - previousWiFiMillis) >= 30 * 1000) && !WiFiAutoAPStarted) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WIFI_Utils::startWiFi();//WiFi.reconnect();
previousWiFiMillis = millis();
if (Config.backupDigiMode) {
wifiCounter++;
}
if (wifiCounter >= 2) {
Serial.println("*** Starting BackUp Digi Mode ***");
backUpDigiMode = true;
lastBackupDigiTime = millis();
if (Config.backupDigiMode) {
wifiCounter++;
}
if (wifiCounter >= 2) {
Serial.println("*** Starting BackUp Digi Mode ***");
backUpDigiMode = true;
lastBackupDigiTime = millis();
}
}
}
}
@@ -58,7 +61,7 @@ namespace WIFI_Utils {
WiFi.mode(WIFI_MODE_NULL);
WiFi.mode(WIFI_AP);
WiFi.softAP(Config.callsign + " AP", Config.wifiAutoAP.password);
WiFi.softAP(Config.callsign + "-AP", Config.wifiAutoAP.password);
WiFiAutoAPTime = millis();
WiFiAutoAPStarted = true;
@@ -70,11 +73,13 @@ namespace WIFI_Utils {
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();
show_display("", "Connecting to Wifi:", "", currentWiFi->ssid + " ...", 0);
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) {
@@ -99,7 +104,7 @@ namespace WIFI_Utils {
currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
start = millis();
Serial.print("\nConnecting to WiFi '"); Serial.print(currentWiFi->ssid); Serial.println("' ...");
show_display("", "Connecting to Wifi:", "", currentWiFi->ssid + " ...", 0);
displayShow("", "Connecting to WiFi:", "", currentWiFi->ssid + " ...", 0);
WiFi.disconnect();
WiFi.begin(currentWiFi->ssid.c_str(), currentWiFi->password.c_str());
}
@@ -110,31 +115,33 @@ namespace WIFI_Utils {
#endif
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Connected as ");
Serial.println(WiFi.localIP());
show_display("", " Connected!!", "" , " loading ...", 1000);
Serial.print(WiFi.localIP());
Serial.print(" / MAC Address: ");
Serial.println(WiFi.macAddress());
displayShow("", " Connected!!", "" , " loading ...", 1000);
} else if (WiFi.status() != WL_CONNECTED) {
startAP = true;
Serial.println("\nNot connected to WiFi! Starting Auto AP");
show_display("", " WiFi Not Connected!", "" , " loading ...", 1000);
displayShow("", " WiFi Not Connected!", "" , " loading ...", 1000);
}
WiFiConnected = !startAP;
if (startAP) {
Serial.println("\nNot connected to WiFi! Starting Auto AP");
show_display("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000);
displayShow("", " Starting Auto AP", " Please connect to it " , " loading ...", 1000);
startAutoAP();
}
}
void checkIfAutoAPShouldPowerOff() {
if (WiFiAutoAPStarted && Config.wifiAutoAP.powerOff > 0) {
void checkAutoAPTimeout() {
if (WiFiAutoAPStarted && Config.wifiAutoAP.timeout > 0) {
if (WiFi.softAPgetStationNum() > 0) {
WiFiAutoAPTime = 0;
} else {
if (WiFiAutoAPTime == 0) {
WiFiAutoAPTime = millis();
} else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.powerOff * 60 * 1000) {
} else if ((millis() - WiFiAutoAPTime) > Config.wifiAutoAP.timeout * 60 * 1000) {
Serial.println("Stopping auto AP");
WiFiAutoAPStarted = false;
@@ -147,7 +154,7 @@ namespace WIFI_Utils {
}
void setup() {
startWiFi();
if (Config.digi.ecoMode == 0) startWiFi();
btStop();
}

View File

@@ -1,13 +1,18 @@
#include "bme_utils.h"
#include <TinyGPS++.h>
#include "configuration.h"
#include "gps_utils.h"
#include "board_pinout.h"
#include "wx_utils.h"
#include "display.h"
#define SEALEVELPRESSURE_HPA (1013.25)
#define CORRECTION_FACTOR (8.2296) // for meters
#define SEALEVELPRESSURE_HPA (1013.25)
#define CORRECTION_FACTOR (8.2296) // for meters
extern Configuration Config;
extern String fifthLine;
#ifdef HAS_GPS
extern TinyGPSPlus gps;
#endif
int wxModuleType = 0;
uint8_t wxModuleAddress = 0x00;
@@ -16,7 +21,7 @@ float newHum, newTemp, newPress, newGas;
Adafruit_BME280 bme280;
#ifdef HELTEC_V3
#if defined(HELTEC_V3) || defined(HELTEC_V3_2)
Adafruit_BMP280 bmp280(&Wire1);
Adafruit_Si7021 sensor = Adafruit_Si7021();
#else
@@ -26,18 +31,17 @@ Adafruit_Si7021 sensor = Adafruit_Si7021();
#endif
namespace BME_Utils {
namespace WX_Utils {
void getWxModuleAddres() {
uint8_t err, addr;
for(addr = 1; addr < 0x7F; addr++) {
#ifdef HELTEC_V3
Wire1.beginTransmission(addr);
err = Wire1.endTransmission();
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
Wire1.beginTransmission(addr);
err = Wire1.endTransmission();
#else
Wire.beginTransmission(addr);
err = Wire.endTransmission();
Wire.beginTransmission(addr);
err = Wire.endTransmission();
#endif
if (err == 0) {
//Serial.println(addr); this shows any connected board to I2C
@@ -53,17 +57,17 @@ namespace BME_Utils {
}
void setup() {
if (Config.bme.active) {
if (Config.wxsensor.active) {
getWxModuleAddres();
if (wxModuleAddress != 0x00) {
bool wxModuleFound = false;
if (wxModuleAddress == 0x76 || wxModuleAddress == 0x77) {
#ifdef HELTEC_V3
if (bme280.begin(wxModuleAddress, &Wire1)) {
Serial.println("BME280 sensor found");
wxModuleType = 1;
wxModuleFound = true;
}
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
if (bme280.begin(wxModuleAddress, &Wire1)) {
Serial.println("BME280 sensor found");
wxModuleType = 1;
wxModuleFound = true;
}
#else
if (bme280.begin(wxModuleAddress)) {
Serial.println("BME280 sensor found");
@@ -93,7 +97,7 @@ namespace BME_Utils {
}
}
if (!wxModuleFound) {
show_display("ERROR", "", "BME/BMP/Si7021 sensor active", "but no sensor found...", 2000);
displayShow("ERROR", "", "BME/BMP/Si7021 sensor active", "but no sensor found...", 2000);
Serial.println("BME/BMP/Si7021 sensor Active in config but not found! Check Wiring");
} else {
switch (wxModuleType) {
@@ -115,7 +119,7 @@ namespace BME_Utils {
Serial.println("BMP280 Module init done!");
break;
case 3:
#ifndef HELTEC_V3
#if !defined(HELTEC_V3) && !defined(HELTEC_V3_2)
bme680.setTemperatureOversampling(BME680_OS_1X);
bme680.setHumidityOversampling(BME680_OS_1X);
bme680.setPressureOversampling(BME680_OS_1X);
@@ -125,12 +129,12 @@ namespace BME_Utils {
break;
}
}
}
}
}
}
String generateTempString(const float bmeTemp) {
String strTemp = String((int)bmeTemp);
String generateTempString(const float sensorTemp) {
String strTemp = String((int)sensorTemp);
switch (strTemp.length()) {
case 1:
return "00" + strTemp;
@@ -143,15 +147,15 @@ namespace BME_Utils {
}
}
String generateHumString(const float bmeHum) {
String strHum = String((int)bmeHum);
String generateHumString(const float sensorHum) {
String strHum = String((int)sensorHum);
switch (strHum.length()) {
case 1:
return "0" + strHum;
case 2:
return strHum;
case 3:
if ((int)bmeHum == 100) {
if ((int)sensorHum == 100) {
return "00";
} else {
return "-99";
@@ -161,9 +165,9 @@ namespace BME_Utils {
}
}
String generatePresString(const float bmePress) {
String strPress = String((int)bmePress);
String decPress = String(int((bmePress - int(bmePress)) * 10));
String generatePresString(const float sensorPres) {
String strPress = String((int)sensorPres);
String decPress = String(int((sensorPres - int(sensorPres)) * 10));
switch (strPress.length()) {
case 1:
return "000" + strPress + decPress;
@@ -195,7 +199,7 @@ namespace BME_Utils {
newHum = 0;
break;
case 3: // BME680
#ifndef HELTEC_V3
#if !defined(HELTEC_V3) && !defined(HELTEC_V3_2)
bme680.performReading();
delay(50);
if (bme680.endReading()) {
@@ -213,14 +217,12 @@ namespace BME_Utils {
break;
}
String wx;
if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) {
Serial.println("BME/BMP/Si7021 Module data failed");
wx = ".../...g...t...r...p...P...h..b.....";
fifthLine = "";
return wx;
return ".../...g...t...";
} else {
String tempStr = generateTempString(((newTemp + Config.bme.temperatureCorrection) * 1.8) + 32);
String tempStr = generateTempString(((newTemp + Config.wxsensor.temperatureCorrection) * 1.8) + 32);
String humStr;
if (wxModuleType == 1 || wxModuleType == 3 || wxModuleType == 4) {
@@ -229,34 +231,35 @@ namespace BME_Utils {
humStr = "..";
}
String presStr;
if (wxModuleAddress == 4) {
presStr = ".....";
} else {
presStr = generatePresString(newPress + (Config.bme.heightCorrection/CORRECTION_FACTOR));
}
String presStr = (wxModuleAddress == 4)
? "....."
#ifdef HAS_GPS
: generatePresString(newPress + (gps.altitude.meters() / CORRECTION_FACTOR));
#else
: generatePresString(newPress + (Config.wxsensor.heightCorrection / CORRECTION_FACTOR));
#endif
fifthLine = "BME-> ";
fifthLine += String(int(newTemp + Config.bme.temperatureCorrection));
fifthLine += String(int(newTemp + Config.wxsensor.temperatureCorrection));
fifthLine += "C ";
fifthLine += humStr;
fifthLine += "% ";
fifthLine += presStr.substring(0,4);
fifthLine += "hPa";
wx = ".../...g...t";
wx += tempStr;
wx += "r...p...P...h";
wx += humStr;
wx += "b";
wx += presStr;
String wxPayload = ".../...g...t";
wxPayload += tempStr;
wxPayload += "h";
wxPayload += humStr;
wxPayload += "b";
wxPayload += presStr;
if (wxModuleType == 3) {
wx += "Gas: ";
wx += String(newGas);
wx += "Kohms";
wxPayload += "Gas: ";
wxPayload += String(newGas);
wxPayload += "Kohms";
}
return wx;
return wxPayload;
}
}

View File

@@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html

View File

@@ -9,8 +9,21 @@ files = [
'data_embed/style.css',
'data_embed/bootstrap.js',
'data_embed/bootstrap.css',
'data_embed/favicon.png',
]
string_to_find_str = "String"
string_to_find_ver = "versionDate"
with open('src/LoRa_APRS_iGate.cpp', encoding='utf-8') as cpp_file:
for line in cpp_file:
if string_to_find_str in line and string_to_find_ver in line:
start = line.find('"') + 1
end = line.find('"', start)
if start > 0 and end > start:
versionDate = line[start:end]
break
for src in files:
out = src + ".gz"
@@ -19,7 +32,7 @@ for src in files:
content = f.read()
if src == 'data_embed/index.html':
env_vars = env["BOARD"] + "<br>" + ','.join(env["BUILD_FLAGS"]).replace('-Werror -Wall,', '').replace(',-DELEGANTOTA_USE_ASYNC_WEBSERVER=1', '')
env_vars = env["BOARD"] + "<br>" + ','.join(env["BUILD_FLAGS"]).replace('-Werror -Wall,', '').replace(',-DELEGANTOTA_USE_ASYNC_WEBSERVER=1', '') + "<br>" + "Version date: " + versionDate
current_date = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') + " UTC"
build_info = f'{env_vars}<br>Build date: {current_date}'.encode()

View File

@@ -0,0 +1,28 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1268
#define RADIO_HAS_XTAL
#define RADIO_SCLK_PIN 6
#define RADIO_MISO_PIN 4
#define RADIO_MOSI_PIN 7
#define RADIO_CS_PIN 5
#define RADIO_DIO1_PIN 3
#define RADIO_RST_PIN -1
#define RADIO_BUSY_PIN 8
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN RADIO_DIO1_PIN
// Display
#define HAS_DISPLAY
#undef OLED_SDA
#undef OLED_SCL
#undef OLED_RST
#define OLED_SDA 0
#define OLED_SCL 1
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#endif

View File

@@ -0,0 +1,10 @@
[env:ESP32_C3_OctopusLab_LoRa]
board = esp32-c3-devkitm-1
board_build.mcu = esp32c3
build_flags =
${common.build_flags}
${common.usb_flags}
-D ESP32_C3_OctopusLab_LoRa
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,33 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1268
#define HAS_1W_LORA
#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
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 2
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_1W_LoRa]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_1W_LoRa
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,33 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1262
#define HAS_1W_LORA
#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
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 2
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_1W_LoRa_915]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_1W_LoRa_915
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,30 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_LLCC68
#define HAS_1W_LORA
#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
// Display
#define HAS_DISPLAY
#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)
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_1W_LoRa_LLCC68]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_1W_LoRa_LLCC68
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,30 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1268
#define HAS_1W_LORA
#define RADIO_SCLK_PIN 5 // https://github.com/NanoVHF/Meshtastic-DIY/tree/main/PCB/ESP-32-devkit_EBYTE-E22/Mesh-v1.02-2LCD-FreePins
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 27
#define RADIO_CS_PIN 18
#define RADIO_RST_PIN 23
#define RADIO_DIO1_PIN 33
#define RADIO_BUSY_PIN 32
#define RADIO_RXEN 14
#define RADIO_TXEN 13
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_33
// Display
#define HAS_DISPLAY
#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)
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_1W_LoRa_Mesh_V1_2]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_1W_LoRa_Mesh_V1_2
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,29 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1278
#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
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 2
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_LoRa]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_LoRa
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,29 @@
#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
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 2
#endif

View File

@@ -0,0 +1,8 @@
[env:ESP32_DIY_LoRa_915]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_LoRa_915
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,34 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1278
#define RADIO_SCLK_PIN 18
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 23
#define RADIO_CS_PIN 2
#define RADIO_RST_PIN 0
#define RADIO_BUSY_PIN 32
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 13 // 13 for V1.1 and 12 for V1.0
#define BATTERY_PIN 35
#define HAS_A7670
#define A7670_PWR_PIN 4
#define A7670_ResetPin 5
#define A7670_TX_PIN 26
#define A7670_RX_PIN 27
#endif

View File

@@ -0,0 +1,10 @@
[env:ESP32_DIY_LoRa_A7670]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_LoRa_A7670
lib_deps =
${common.lib_deps}
${common.display_libs}
vshymanskyy/TinyGSM @ 0.12.0
vshymanskyy/StreamDebugger @ 1.0.1

View File

@@ -0,0 +1,34 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1276
#define RADIO_SCLK_PIN 18
#define RADIO_MISO_PIN 19
#define RADIO_MOSI_PIN 23
#define RADIO_CS_PIN 2
#define RADIO_RST_PIN 0
#define RADIO_BUSY_PIN 32
// Display
#define HAS_DISPLAY
#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)
// Aditional Config
#define INTERNAL_LED_PIN 13 // 13 for V1.1 and 12 for V1.0
#define BATTERY_PIN 35
#define HAS_A7670
#define A7670_PWR_PIN 4
#define A7670_ResetPin 5
#define A7670_TX_PIN 26
#define A7670_RX_PIN 27
#endif

View File

@@ -0,0 +1,10 @@
[env:ESP32_DIY_LoRa_A7670_915]
board = esp32dev
build_flags =
${common.build_flags}
-D ESP32_DIY_LoRa_A7670_915
lib_deps =
${common.lib_deps}
${common.display_libs}
vshymanskyy/TinyGSM @ 0.12.0
vshymanskyy/StreamDebugger @ 1.0.1

View File

@@ -0,0 +1,30 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1268
#define HAS_1W_LORA
#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 33
#define RADIO_BUSY_PIN 26
#define RADIO_RXEN 14
#define RADIO_TXEN 13
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_33
// Display
#define HAS_DISPLAY
#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)
#endif

View File

@@ -0,0 +1,8 @@
[env:OE5HWN_MeshCom]
board = esp32dev
build_flags =
${common.build_flags}
-D OE5HWN_MeshCom
lib_deps =
${common.lib_deps}
${common.display_libs}

View File

@@ -0,0 +1,35 @@
#ifndef BOARD_PINOUT_H_
#define BOARD_PINOUT_H_
// LoRa Radio
#define HAS_SX1268
#define RADIO_VCC_PIN 21
#define RADIO_SCLK_PIN 12
#define RADIO_MISO_PIN 13
#define RADIO_MOSI_PIN 11
#define RADIO_CS_PIN 10
#define RADIO_RST_PIN 9
#define RADIO_DIO1_PIN 5
#define RADIO_BUSY_PIN 6
#define RADIO_RXEN 42
#define RADIO_TXEN 14
#define RADIO_WAKEUP_PIN RADIO_DIO1_PIN
#define GPIO_WAKEUP_PIN GPIO_SEL_5
// Display
#define HAS_DISPLAY
#undef OLED_SDA
#undef OLED_SCL
#undef OLED_RST
#define OLED_SDA 3
#define OLED_SCL 4
#define OLED_RST -1 // Reset pin # (or -1 if sharing Arduino reset pin)
// Aditional Config
#define INTERNAL_LED_PIN 16
#define BATTERY_PIN 1
#define BUTTON_PIN 0
#endif

View File

@@ -0,0 +1,10 @@
[env:QRPLabs_LightGateway_1_0]
board = esp32-s3-devkitc-1
board_build.mcu = esp32s3
build_flags =
${common.build_flags}
${common.usb_flags}
-D LIGHTGATEWAY_1_0
lib_deps =
${common.lib_deps}
${common.display_libs}

Some files were not shown because too many files have changed in this diff Show More