Compare commits
534 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b7e0fdcef | |||
| ad996c8a49 | |||
| dedd7152d9 | |||
| 5f5d7d7868 | |||
| 2e3cafd0f0 | |||
| 1c07c2fb2b | |||
| 4c63dd8bb7 | |||
| b00fba9693 | |||
| 37162b9708 | |||
| 44d9732aa2 | |||
| 312bdc9d9f | |||
| ff0b96bfe4 | |||
| 36a8ef0ffb | |||
| 5ce8059040 | |||
| 60aef00b24 | |||
| 72c2c144ae | |||
| a1c552f197 | |||
| 8ede848199 | |||
| a4a82b75c5 | |||
| 64ac924f1f | |||
| bde4a7f042 | |||
| d54b63df22 | |||
| c3d94d673a | |||
| 45edf2ffa3 | |||
| d628de9c9c | |||
| f879182f62 | |||
| c9ed618a8b | |||
| 6c7b8f9918 | |||
| c2b4b3b92f | |||
| f7319ce591 | |||
| 858162eb9c | |||
| 100b002309 | |||
| 3acf73bf5f | |||
| 53675e8084 | |||
| 4349019f7b | |||
| 411753c0aa | |||
| ad6aed7f0d | |||
| f325c54fc3 | |||
| 1a3966eadc | |||
| ffd3eaeb49 | |||
| df03a49123 | |||
| 58d647bad1 | |||
| 59988fbaf1 | |||
| 1ad13e3c09 | |||
| ffe1a2f830 | |||
| a0fdd78cb1 | |||
| 95e437cb50 | |||
| 9c488991e2 | |||
| ddcd33b94a | |||
| b688391a0e | |||
| 56d63d0389 | |||
| ad5a5ccf18 | |||
| 92bc0a7667 | |||
| ffcfc42b8a | |||
| f3e0830473 | |||
| 62107a5b4a | |||
| 9801545965 | |||
| dd89f56436 | |||
| 27593d8718 | |||
| 008575b422 | |||
| b8eedabe9a | |||
| 7371b8e37a | |||
| 44605e82c2 | |||
| 0360085131 | |||
| 57f720b0d1 | |||
| 3d01ea03c0 | |||
| afb6a60bfe | |||
| 06ef37e4dc | |||
| 9159362796 | |||
| 47c136fdd5 | |||
| 970d743b80 | |||
| 7c5e58f3b2 | |||
| 210c7acb70 | |||
| 8d102a73c1 | |||
| 5030d2d645 | |||
| a95f55273f | |||
| 4014db03c8 | |||
| d96d5f1963 | |||
| d1cb732ae1 | |||
| 1504bf5a7f | |||
| 3c27e52df7 | |||
| 3d5f3a4914 | |||
| db6292ce59 | |||
| 7995d23779 | |||
| 7f150bc4a0 | |||
| ff5650f0c5 | |||
| a91f0f3f3c | |||
| c9577b6c21 | |||
| 10cb7c6e45 | |||
| 99052e594a | |||
| a05917c494 | |||
| e2e935797f | |||
| 5ceff0064f | |||
| 8beb7c0465 | |||
| 112e38312d | |||
| 5a1c6e7ed9 | |||
| 0defd5b289 | |||
| cdac54c34e | |||
| 71e98487f6 | |||
| 510b5bdc59 | |||
| 00db358cc3 | |||
| c0641986aa | |||
| 55378bb9f3 | |||
| 79cf50a630 | |||
| 03ccd2b12e | |||
| d5ffd26c3c | |||
| 2f0f991785 | |||
| 975b140c73 | |||
| f2abe34af1 | |||
| a786d83b9e | |||
| bf0a0d6e4c | |||
| d08e5b1b27 | |||
| f387e03b53 | |||
| 16215f9e56 | |||
| ce01d0aa4d | |||
| b0a05f89f6 | |||
| 58d8736969 | |||
| df9060d906 | |||
| 2bd6844d89 | |||
| 0a79b6459b | |||
| d5eb32a38b | |||
| d6c5741fde | |||
| 1063a82294 | |||
| 6913b6b89f | |||
| 42c990f5cf | |||
| a17900e4d0 | |||
| 3fd819bd4e | |||
| 640166a50b | |||
| a9bcae62e2 | |||
| 3e0368383a | |||
| 8b790ef656 | |||
| c110b41b99 | |||
| be7fe23cd5 | |||
| 202d03c61f | |||
| ddb45544db | |||
| c9ea51c6da | |||
| 72fd2b45ec | |||
| 0e46c64880 | |||
| dd12330e85 | |||
| 2edb183cad | |||
| 775677d5e8 | |||
| a60a6d6e4b | |||
| 14abe14703 | |||
| 345fb1e937 | |||
| 916eb038e5 | |||
| 40fc177828 | |||
| 5dc6e99972 | |||
| db5710ec6a | |||
| 65acb54dbe | |||
| 6088c61e73 | |||
| a8c972c5e1 | |||
| bd3a9f91d6 | |||
| 643a18f40c | |||
| 46e5bdd21e | |||
| ea426f4126 | |||
| 5cbdd318a2 | |||
| 735988ee1c | |||
| d5b666f458 | |||
| 702f4abcbb | |||
| d0070e4381 | |||
| f4744eab6a | |||
| bd672857f4 | |||
| 9cc26ccdae | |||
| 8863838210 | |||
| f11b6de57a | |||
| 55d6bc325f | |||
| ee687e6959 | |||
| d1732a6bba | |||
| 4fb4712a33 | |||
| 39276b0d32 | |||
| 22203a7c24 | |||
| d8d832fde9 | |||
| 61db6c3132 | |||
| 9521a357b1 | |||
| ee95931f00 | |||
| 60aa2b05ac | |||
| bc5183a192 | |||
| 1019306c7c | |||
| fbe00903ad | |||
| 291a6bc80e | |||
| 3b550c7f81 | |||
| 4659f8b2ff | |||
| 62d157d7f0 | |||
| b0e116ee1d | |||
| 00b12c2bf5 | |||
| 85b21565db | |||
| b9e2c0e8f0 | |||
| b763b4af78 | |||
| 5553e7ae5c | |||
| 1afd039c3f | |||
| 1888084f31 | |||
| dc92b822c8 | |||
| 3c305259e0 | |||
| 497d648c17 | |||
| d267f6699c | |||
| 16ce6bc6d2 | |||
| 008b6250ea | |||
| ddb83d1368 | |||
| 26e2dec2b2 | |||
| 174507377b | |||
| 864ed44a5d | |||
| 5d69cfbe1c | |||
| e57d356fd1 | |||
| 8381f0916c | |||
| beca09293a | |||
| dcca18eeac | |||
| 2494acea55 | |||
| 0c50ce8de4 | |||
| 2f07d35861 | |||
| 91240c5be6 | |||
| b4308a95d5 | |||
| 6c301795d6 | |||
| 5f0c6f4986 | |||
| 7c989e6e9e | |||
| 2bcda6d3a4 | |||
| 848492dc36 | |||
| 413bef67fb | |||
| 3fa4c9371a | |||
| e846c38f97 | |||
| b8446e3f1d | |||
| c3984bc8da | |||
| 601b72da9f | |||
| 5d9493314d | |||
| 86cf12d6c1 | |||
| e5e2c6a980 | |||
| 3b9d49c5f9 | |||
| ab9443140b | |||
| ad1129c588 | |||
| 8bb0b0446c | |||
| 6b1d319901 | |||
| 1ceaf159ba | |||
| f1de8d2df0 | |||
| b9b4f46c66 | |||
| 22b2c679d2 | |||
| 7baa98bf7e | |||
| 35e79709e3 | |||
| f4bae74c26 | |||
| 04e721ac5a | |||
| 1922d7453b | |||
| f1bd751585 | |||
| c346bc0f39 | |||
| bbc1996918 | |||
| 505bb3d5a4 | |||
| b97457146a | |||
| 64b51fea72 | |||
| d82cf9235d | |||
| d83bb19bc8 | |||
| 0feb0045d0 | |||
| 4999c89820 | |||
| f5048edf84 | |||
| 691f60925a | |||
| 4bf4e781df | |||
| 0c09f5a934 | |||
| 494be4a393 | |||
| 16e79d291c | |||
| c9a52d5b61 | |||
| 7d813524e3 | |||
| 2d7d02f2df | |||
| 562b0a46ea | |||
| 69c074a834 | |||
| bf04507ed0 | |||
| e653d39004 | |||
| 68edade5b4 | |||
| 685d629ef6 | |||
| b7f6d84ac8 | |||
| dda4b06714 | |||
| 6095b4ff72 | |||
| f77d7078b6 | |||
| 1dc1a291cd | |||
| 4396078d76 | |||
| 9924fb9a38 | |||
| 72a6c48553 | |||
| 217e5b07e1 | |||
| ce7ed2519f | |||
| 72f0c80a29 | |||
| 62db4c18da | |||
| 7e91317730 | |||
| 49cffe7d0c | |||
| 7537c1ee50 | |||
| b2a8def481 | |||
| b3441ece02 | |||
| 6ee86f7557 | |||
| 0f5330141f | |||
| d04b009a49 | |||
| 397a94cc47 | |||
| a8e1a48d62 | |||
| d75be8f007 | |||
| c89ca7316f | |||
| 18de124c04 | |||
| 01cee5d51e | |||
| 005f114a97 | |||
| e133d50cd9 | |||
| d3ebe43ebb | |||
| c67f5b60e5 | |||
| d2923cc0b6 | |||
| a87cc0be58 | |||
| e63d54d9f0 | |||
| f6793c01c4 | |||
| 12bcc76452 | |||
| 4cf3a333c9 | |||
| c5217842ff | |||
| e9bb0391f2 | |||
| edd2ff65b9 | |||
| dcc0340c90 | |||
| 4aa8f1aba8 | |||
| 7c7b8507eb | |||
| 3d1ae2fa70 | |||
| 095cc7edae | |||
| c1d1069785 | |||
| bc29afa94e | |||
| eeba0df050 | |||
| 8f40563ae5 | |||
| 8bcf95548c | |||
| 6809d96b59 | |||
| 09bf14f8d1 | |||
| 666c57738b | |||
| e4d41380bf | |||
| afdde6ad2d | |||
| f7ce94c494 | |||
| ce69b0c950 | |||
| 6e381fe7fc | |||
| dcc549c5ba | |||
| 618be275af | |||
| 2c71e3ed65 | |||
| 3589f54d02 | |||
| c6687529da | |||
| 3c2c49aa01 | |||
| 9044b93090 | |||
| 076f3bfcb5 | |||
| c6888adca8 | |||
| b06b91d258 | |||
| bbdcf8ce0d | |||
| 992641578d | |||
| f70d836285 | |||
| d50b0767c4 | |||
| fc8d3fd9fb | |||
| 345a6c2c21 | |||
| 5986125661 | |||
| 6090b83d34 | |||
| 7cc1a759cc | |||
| 51f9e0f0cc | |||
| 960df01d61 | |||
| 60a8fe01a3 | |||
| 46d8b12896 | |||
| 5296b19ef2 | |||
| 35fbd7a5dc | |||
| adf4c1fcb8 | |||
| 0921d01340 | |||
| 0c81df7cc5 | |||
| 789b3732f3 | |||
| 8be573e2b6 | |||
| 7022046f21 | |||
| d19284df12 | |||
| 05a5c096c3 | |||
| 7add09d346 | |||
| 9e87c50966 | |||
| 9a33df49e3 | |||
| 916cbade8c | |||
| 2496c12763 | |||
| 166773b81d | |||
| b8d000356a | |||
| 49d3801e83 | |||
| 9dead41e79 | |||
| f3eaa28c76 | |||
| 1bdfa3a117 | |||
| 8af1f4cea3 | |||
| d3e45c57e0 | |||
| 8024925950 | |||
| 8e6346aa97 | |||
| cfca59cf20 | |||
| 2430f92193 | |||
| 3cef4676a7 | |||
| 87a1830970 | |||
| b8fb7cfba0 | |||
| 3b81460798 | |||
| 630ec062c1 | |||
| dc39eec941 | |||
| bdf3fe7cbc | |||
| 3de3aac026 | |||
| 3a148fa55d | |||
| c7e79eba43 | |||
| 8429bb4730 | |||
| c940cb99d9 | |||
| 0be60b76b0 | |||
| 794cc0640f | |||
| c5dcfd86b2 | |||
| 4d4598e09e | |||
| 2e4ee4792e | |||
| bee09386e1 | |||
| 0a15813ef2 | |||
| 6ecb733bea | |||
| 1345ddd608 | |||
| 5c0fba60b5 | |||
| 67c2a61f09 | |||
| f1e712a363 | |||
| 7753618756 | |||
| 61168d9217 | |||
| d9af677f69 | |||
| cc976a4a4a | |||
| e6402409fc | |||
| 12860410fd | |||
| 886b661a62 | |||
| 53461f289c | |||
| 54496a9f86 | |||
| 5e0294fb14 | |||
| d7c1c70f10 | |||
| ad507cb4c9 | |||
| c54843622c | |||
| 2d820bbcc4 | |||
| 691f967aaf | |||
| 3b85a3a5bf | |||
| 983467e059 | |||
| 2b6066f62e | |||
| b81d986c58 | |||
| 71c5e608b6 | |||
| db24293b91 | |||
| 611ea87264 | |||
| 04a7f89891 | |||
| d744f0a0f0 | |||
| a14c570db0 | |||
| 708742f43d | |||
| e182dd163e | |||
| b2b388da99 | |||
| c6929e161a | |||
| 26e4984225 | |||
| fe41189418 | |||
| 9742e25100 | |||
| e2c3edd0f1 | |||
| ffc3bd7624 | |||
| 7743cbe221 | |||
| da0178bc56 | |||
| 5f145751c0 | |||
| cda72194db | |||
| 47e6623881 | |||
| 7e4fdff0a3 | |||
| eb472b1506 | |||
| f2a6bbf0a9 | |||
| 3df25d71e2 | |||
| 1b5a89b31b | |||
| bd8c8e2eb1 | |||
| 2b0cc514f0 | |||
| deb4ea6974 | |||
| 5333a68d04 | |||
| 7ab5ffa81d | |||
| 3964354844 | |||
| 1eee529f9f | |||
| 38b81ffbd7 | |||
| 7dfbaf45ef | |||
| 13adc2d2d0 | |||
| ce088035ff | |||
| 4eb46d59f6 | |||
| 2cbb6c1a1a | |||
| 507a365b88 | |||
| 5f04468285 | |||
| fc2a35a058 | |||
| 7987ceb262 | |||
| 8f1629abbc | |||
| b4f2daca42 | |||
| ce058ed424 | |||
| b00b29a5da | |||
| a64899d44c | |||
| af9f3fd09b | |||
| 0fb2c95338 | |||
| 3885a43324 | |||
| 0695e6643e | |||
| 71473164f4 | |||
| 8e505df768 | |||
| 81295bc3e2 | |||
| 16f5338953 | |||
| 0b22d27b40 | |||
| aea0aa21af | |||
| a6ce44f8d3 | |||
| 3ce5d08c44 | |||
| 51b59ab555 | |||
| b9024d34cb | |||
| e4bc8eecbe | |||
| c10645c2c0 | |||
| 0d64c65aa5 | |||
| d16e407269 | |||
| c8cde0a404 | |||
| c1cc7c9ab0 | |||
| 4d23681935 | |||
| 1bcb119cad | |||
| 43c0021ba7 | |||
| daa245ff7c | |||
| e52ac86e3e | |||
| c1bb6e39ef | |||
| 0e94444198 | |||
| 968d9188be | |||
| db21a08904 | |||
| 14999d1b66 | |||
| a8a7c3e3a3 | |||
| ca3c1eaf9f | |||
| dec018f232 | |||
| f49472efd1 | |||
| df3b15ff35 | |||
| d004efb193 | |||
| d98334a489 | |||
| 1365ae67a1 | |||
| 110c6d600b | |||
| 9557df983b | |||
| 0e9dba76a8 | |||
| caa48694b4 | |||
| 0ac2705609 | |||
| ed9d80fd78 | |||
| cb7e9f3235 | |||
| 8fdab82684 | |||
| 0d1162786c | |||
| 0b40cb0889 | |||
| e33b639f12 | |||
| 15be5fc611 | |||
| a44c6ca96c | |||
| 7897e9a5be | |||
| a33875a608 | |||
| 5337cb2d46 | |||
| 67e1c528f3 | |||
| 9f617c406e | |||
| d9629d0929 | |||
| 2a5cc33711 | |||
| 6bd6cce82b | |||
| 54bbede56c | |||
| 85b7596cbb | |||
| fb4b6a25bd | |||
| 4c30422635 | |||
| e059c65a99 | |||
| 3fda399ecf | |||
| 492f571183 | |||
| b287704293 | |||
| d802fb4c91 | |||
| 4247d00be4 | |||
| 7401c36fdf | |||
| cc2d4a669d | |||
| 706d84cf07 | |||
| 4ae33a8362 |
@@ -11,16 +11,84 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target:
|
target:
|
||||||
- "ttgo-lora32-v21"
|
- name: ttgo-lora32-v21
|
||||||
- "heltec-lora32-v2"
|
chip: esp32
|
||||||
- "heltec_wifi_lora_32_V3"
|
- name: ttgo-lora32-v21_915
|
||||||
- "ESP32_DIY_LoRa"
|
chip: esp32
|
||||||
- "ESP32_DIY_1W_LoRa"
|
- name: ttgo_lora32_t3s3_v1_2
|
||||||
- "ttgo-t-beam-v1_2"
|
chip: esp32s3
|
||||||
- "ttgo-t-beam-v1"
|
- name: heltec-lora32-v2
|
||||||
- "ttgo-t-beam-v1_SX1268"
|
chip: esp32
|
||||||
- "ttgo-t-beam-v1_2_SX1262"
|
- name: heltec_wifi_lora_32_V3
|
||||||
# - "heltec_wireless_stick_lite" # NOT FULLY TESTED
|
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
|
||||||
|
chip: esp32
|
||||||
|
- name: ESP32_DIY_1W_LoRa
|
||||||
|
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
|
||||||
|
chip: esp32
|
||||||
|
- name: ttgo-t-beam-v1
|
||||||
|
chip: esp32
|
||||||
|
- name: ttgo-t-beam-v1_915
|
||||||
|
chip: esp32
|
||||||
|
- name: ttgo-t-beam-v1_SX1268
|
||||||
|
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
|
||||||
|
chip: esp32
|
||||||
|
- name: heltec_wireless_tracker
|
||||||
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
@@ -32,19 +100,70 @@ jobs:
|
|||||||
run: pip install --upgrade platformio
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
- name: Build target
|
- name: Build target
|
||||||
run: pio run -e ${{ matrix.target }}
|
run: |
|
||||||
|
pio run -e ${{ matrix.target.name }}
|
||||||
|
|
||||||
- name: Build FS
|
- name: Build FS
|
||||||
run: pio run --target buildfs -e ${{ matrix.target }}
|
run: |
|
||||||
|
pio run --target buildfs -e ${{ matrix.target.name }}
|
||||||
|
|
||||||
- name: Move Files
|
- name: Move Files
|
||||||
run: |
|
run: |
|
||||||
mkdir -p installer/firmware
|
mkdir -p installer/firmware
|
||||||
cp .pio/build/${{ matrix.target }}/firmware.bin installer/firmware/
|
cp .pio/build/${{ matrix.target.name }}/firmware.bin installer/ota_update.bin
|
||||||
cp .pio/build/${{ matrix.target }}/bootloader.bin installer/firmware/
|
cp .pio/build/${{ matrix.target.name }}/firmware.bin installer/firmware/
|
||||||
cp .pio/build/${{ matrix.target }}/partitions.bin installer/firmware/
|
cp .pio/build/${{ matrix.target.name }}/bootloader.bin installer/firmware/
|
||||||
cp .pio/build/${{ matrix.target }}/spiffs.bin installer/firmware/
|
cp .pio/build/${{ matrix.target.name }}/partitions.bin installer/firmware/
|
||||||
|
cp .pio/build/${{ matrix.target.name }}/spiffs.bin installer/firmware/
|
||||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin installer/firmware/
|
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin installer/firmware/
|
||||||
|
|
||||||
|
- name: Merge for web flashing
|
||||||
|
run: |
|
||||||
|
if [ "${{ matrix.target.chip }}" == "esp32" ]; then
|
||||||
|
python installer/bin/esptool/esptool.py --chip esp32 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 }}" == "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 \
|
||||||
|
--flash_mode dio \
|
||||||
|
--flash_freq 40m \
|
||||||
|
--flash_size 8MB \
|
||||||
|
0x0000 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 }}" == "esp32c3" ]; then
|
||||||
|
python installer/bin/esptool/esptool.py --chip esp32c3 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
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Install Zip
|
- name: Install Zip
|
||||||
run: sudo apt-get install zip
|
run: sudo apt-get install zip
|
||||||
@@ -59,5 +178,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
upload_url: ${{ github.event.release.upload_url }}
|
upload_url: ${{ github.event.release.upload_url }}
|
||||||
asset_path: ./installer.zip
|
asset_path: ./installer.zip
|
||||||
asset_name: ${{ matrix.target }}.zip
|
asset_name: ${{ matrix.target.name }}.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Commit Test Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- name: ttgo-lora32-v21
|
||||||
|
chip: esp32
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
|
- name: Install PlatformIO Core
|
||||||
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
|
- name: Build target
|
||||||
|
run: pio run -e ${{ matrix.target.name }}
|
||||||
|
|
||||||
|
- name: Build FS
|
||||||
|
run: pio run --target buildfs -e ${{ matrix.target.name }}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.formatOnSave": true
|
"editor.formatOnSave": false
|
||||||
}
|
}
|
||||||
@@ -1,80 +1,129 @@
|
|||||||
# 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.
|
This firmware is for using ESP32 based boards with LoRa Modules and GPS to live in the APRS world.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
__(NOTE: This iGate Firmware was develop to work with all LoRa APRS Trackers and specially with this firmware <a href="https://github.com/richonguzman/LoRa_APRS_Tracker" target="_blank">LoRa APRS Tracker</a>)__
|
__(This iGate Firmware works with all LoRa Tracker Firmwares (specially this <a href="https://github.com/richonguzman/LoRa_APRS_Tracker" target="_blank">LoRa APRS Tracker Firmware</a>))__
|
||||||
|
<br />
|
||||||
|
|
||||||
___________________________________________________
|
____________________________________________________
|
||||||
|
|
||||||
## You can support this project to continue to grow:
|
## You can support this project to continue to grow:
|
||||||
|
|
||||||
[<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/github-sponsors.png">](https://github.com/sponsors/richonguzman) [<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/blob/main/images/paypalme.png">](http://paypal.me/richonguzman)
|
[<img src="https://github.com/richonguzman/LoRa_APRS_Tracker/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 />
|
||||||
|
|
||||||
This next generation LoRa iGate can work as:
|
# WEB FLASHER/INSTALLER is <a href="https://richonguzman.github.io/lora-igate-web-flasher/installer.html" target="_blank">here</a>
|
||||||
- pure RX-iGate,
|
|
||||||
- Rx+Tx-iGate and distribute messages and weather forecasts to heard trackers, and
|
|
||||||
- Digipeater in simplex or split-frequency environment.
|
|
||||||
|
|
||||||
In all configurations the display shows the current stationMode, heard packets and events the iGate is currently performing.
|
|
||||||
|
|
||||||
But under the hood is much more:
|
|
||||||
|
|
||||||
- Web Configuration UI.
|
|
||||||
- Sending events to remote syslog server.
|
|
||||||
- OTA update capability (for Firmware and Filesystem).
|
|
||||||
- RX first, TX will only be done if there is no traffic on the frequency.
|
|
||||||
- automatic update of the Lora symbol at APRS-IS, black "L" for pure RX, red "L" for TX capability, green star "L" for digipeater and blue round "L" for WX iGate.
|
|
||||||
- support for multiple WLAN with corresponding coordinates.
|
|
||||||
- support for BME/BMP280 and BME680 sensors, sending to WX data to APRS-IS.
|
|
||||||
|
|
||||||
and more will come:
|
|
||||||
- More Web UI Station Information
|
|
||||||
|
|
||||||
____________________________________________________
|
____________________________________________________
|
||||||
|
|
||||||
# WIKI
|
# WIKI
|
||||||
|
|
||||||
### 1. Installation Guide --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/1.-Installation-Guide" target="_blank">here</a>.
|
### FAQ, BME280, TNC and more --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/00.-FAQ-(frequently-asked-questions)" target="_blank">here</a>.
|
||||||
|
|
||||||
### 2. iGate Configuration and Explanation for each setting --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/2.-iGate-Configuration" target="_blank">here</a>.
|
### Installation Guide --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/01.-Installation-Guide" target="_blank">here</a>.
|
||||||
|
<br />
|
||||||
|
|
||||||
### 3. Supported Boards and Environment Selection --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/3.-Supported-Boards-and-Environment-Selection" target="_blank">here</a>.
|
# SUPPORTED BOARDS
|
||||||
|
|
||||||
### 4. Upload Firmware and Filesystem --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/4.-Upload-Firmware-and-Filesystem" target="_blank">here</a>.
|
### Buying links --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/108.-Supported-Boards-and-Buying-Links" target="_blank">here</a>.
|
||||||
|
|
||||||
### 5. Adding BME280 Module --> <a href="https://github.com/richonguzman/LoRa_APRS_iGate/wiki/5.-Adding-BME280-Module" target="_blank">here</a>.
|
(NOTE: all boards with 433-868-915 MHz versions)
|
||||||
|
|
||||||
|
- 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).
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- ESP32C3 + Ebyte 400M30S(or 900M30S) 1W LoRa Module for another DIY version.
|
||||||
|
|
||||||
|
- ESP32 + 4G/LTE A7670 Modem + SX1278 DIY Version.
|
||||||
|
|
||||||
|
- Wemos Lolin32 Oled + SX1278 DIY Version.
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
____________________________________________________
|
|
||||||
## Timeline (Versions):
|
## Timeline (Versions):
|
||||||
|
|
||||||
|
- 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-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).
|
||||||
|
- 2024.05.13 PacketBuffer for Rx (25 Seg).
|
||||||
|
- 2024.05.11 HELTEC Wireless Tracker support added.
|
||||||
|
- 2024.04.23 T-LoRa32 v1.6/v2.1 with 915MHz support added.
|
||||||
|
- 2024.04.23 ESP32 + 4G/LTE MODEM A7670SA + LoRa (SX1278) support added.
|
||||||
|
- 2024.04.22 Wemos Lolin32 OLED DIY LoRa support added .
|
||||||
|
- 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/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).
|
- 2024.02.25 New Web Configuration UI with WiFi AP (thanks Damian SQ2CPA).
|
||||||
- 2023.01.28 Updated to ElegantOTA v.3 (AsyncElegantOTA was deprecated).
|
- 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.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.11 Added iGate Mode to enable APRS-IS and LoRa beacon report at the same time.
|
||||||
- 2024.01.05 Added support for Lilygo TTGO T-Beam V1, V1.2, V1 + SX1268, V1.2 + SX1262.
|
- 2024.01.05 Lilygo TTGO T-Beam V1, V1.2, V1 + SX1268, V1.2 + SX1262 support added.
|
||||||
- 2024.01.02 Added support for EByte 400M30S 1Watt LoRa module for DIY ESP32 iGate.
|
- 2024.01.02 EByte 400M30S 1 Watt LoRa module for DIY ESP32 iGate support added.
|
||||||
- 2023.12.27 HELTEC V3 board support added. Thanks Luc ON2ON.
|
- 2023.12.27 HELTEC V3 board support added. Thanks Luc ON2ON.
|
||||||
- 2023.12.26 Added BME680 module to BME/BMP280 modules supported.
|
- 2023.12.26 BME680 module support added.
|
||||||
- 2023.12.07 MIC-E process and syslog added.
|
- 2023.12.07 MIC-E process and Syslog added.
|
||||||
- 2023.12.06 HELTEC V2 board support added.
|
- 2023.12.06 HELTEC V2 board support added.
|
||||||
- 2023.11.26 Small correction to enable Syslog in stationMode5.
|
- 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 Added Support also for BMP280 module.
|
- 2023.10.09 BMP280 module support added.
|
||||||
- 2023.08.20 Added External Voltage Measurement (Max 15V!)
|
- 2023.08.20 Added External Voltage Measurement (Max 15V!)
|
||||||
- 2023.08.05 Ground Height Correction for Pressure readings added.
|
- 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.16 Small OTA, BME module update.
|
||||||
- 2023.07.05 Adding monitor info of Battery connected.
|
- 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.18 Info on Oled Screen mayor update, added RSSI and Distance to Listened Station.
|
||||||
- 2023.06.17 Support for BME280 Module (Temperature, Humidity, Pressure) added.
|
- 2023.06.17 BME280 Module (Temperature, Humidity, Pressure) support added.
|
||||||
- 2023.06.12 Syslog added.
|
- 2023.06.12 Syslog added.
|
||||||
- 2023.06.10 OTA update support for Firmware and Filesystem.
|
- 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.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.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.
|
- 2023.05.19 Saving Last-Heard Stations for validating Tx Responses.
|
||||||
@@ -83,54 +132,6 @@ ____________________________________________________
|
|||||||
- 2023.02.17 Receiving Feed from APRS-IS.
|
- 2023.02.17 Receiving Feed from APRS-IS.
|
||||||
- 2023.02.10 First Beta (receiving LoRa Beacon/Packets and uploading to APRS-IS).
|
- 2023.02.10 First Beta (receiving LoRa Beacon/Packets and uploading to APRS-IS).
|
||||||
|
|
||||||
____________________________________________________
|
|
||||||
|
|
||||||
|
|
||||||
Instructions (add your information into the '/data/igate_conf.json'):
|
|
||||||
|
|
||||||
a) Change _callsign_ from "NOCALL-10" to your CALLSIGN + SSID.
|
|
||||||
|
|
||||||
b) Choose _stationMode_:
|
|
||||||
|
|
||||||
1 = RX iGate, black "L" as symbol
|
|
||||||
|
|
||||||
2 = Rx + TX iGate, red "L" as symbol, HAM only. RX will be sent to APRS-IS, Messages will be sent via Lora. Same frequency for RX and TX. By using this feature you have comply with the regulations of your country.
|
|
||||||
|
|
||||||
3 = Digipeater simplex, green "L" as symbol, HAM only. Received packets containing WIDEx-x in path will be digipeated on the same frequency. By using this feature you have comply with the regulations of your country.
|
|
||||||
|
|
||||||
4 = Digipeater split frequency, green "L" as symbol, HAM only. Received packets will be digipeated on a different frequency. Frequency separation must be 125kHz or more. By using this feature you have comply with the regulations of your country.
|
|
||||||
|
|
||||||
IgateComment and DigirepeaterComment will be sent to APRS-IS or via RF, depending on your stationmode
|
|
||||||
|
|
||||||
c) WiFi section:
|
|
||||||
|
|
||||||
adjust SSID and Password to you WiFi, add the GPS to "Latitude" and "Longitude" (info from GoogleMaps) of your new LoRa iGate. (If stationMode 3 or 4 selected, add also GPS info to Digirepeater Section).
|
|
||||||
|
|
||||||
d) APRS_IS section:
|
|
||||||
|
|
||||||
change "passcode" from "VWXYZ" to yours (remember that is 5 digits integer) and choose a server close to your location (see https://www.aprs2.net/)
|
|
||||||
|
|
||||||
e) LORA section:
|
|
||||||
|
|
||||||
adjust TX frequency and RX frequency matching your stationmode and country. Remember,
|
|
||||||
|
|
||||||
at stationmode 1, 2, and 3, RX and TX frequency shall be set to 433775000 (443.775MHz, deviations possible, depending on your country)
|
|
||||||
|
|
||||||
at stationmode 4, RX frequency shall be set to 433775000, TX frequency shall be set to 433900000 (deviations possible, depending on your country). There must be a frequency separation of 125kHz or more.
|
|
||||||
|
|
||||||
adjust power to your need, valid values are from 1 to 20
|
|
||||||
|
|
||||||
f) Syslog section:
|
|
||||||
|
|
||||||
adjust server and port to a suitable value if needed.
|
|
||||||
|
|
||||||
g) BME section:
|
|
||||||
|
|
||||||
adjust to "active" if BME280 sensor connected through I2C pins
|
|
||||||
|
|
||||||
|
|
||||||
__________________________________________
|
__________________________________________
|
||||||
|
|
||||||
Special Thanks to the help in testing and developing to Manfred (DC2MH) , for showing me the "way of good coding" to Tihomir (CA3TSK) and much more Ham Licence Ops all over the world.
|
# Hope You Enjoy this, 73! CA2RXU, Valparaiso, Chile
|
||||||
|
|
||||||
# Hope You Enjoy this, 73 !! CA2RXU , Valparaiso, Chile
|
|
||||||
@@ -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
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
"wifi": {
|
"wifi": {
|
||||||
"autoAP": {
|
"autoAP": {
|
||||||
"password": "1234567890",
|
"password": "1234567890",
|
||||||
"powerOff": 10
|
"timeout": 10
|
||||||
},
|
},
|
||||||
"AP": []
|
"AP": []
|
||||||
},
|
},
|
||||||
@@ -13,21 +13,23 @@
|
|||||||
"comment": "LoRa APRS",
|
"comment": "LoRa APRS",
|
||||||
"interval": 15,
|
"interval": 15,
|
||||||
"overlay": "L",
|
"overlay": "L",
|
||||||
"symbol": "#",
|
"symbol": "a",
|
||||||
"path": "WIDE1-1",
|
"path": "WIDE1-1",
|
||||||
"sendViaAPRSIS": false,
|
"sendViaAPRSIS": false,
|
||||||
"sendViaRF": false
|
"sendViaRF": false
|
||||||
},
|
},
|
||||||
"digi": {
|
|
||||||
"mode": 0
|
|
||||||
},
|
|
||||||
"aprs_is": {
|
"aprs_is": {
|
||||||
"active": false,
|
"active": false,
|
||||||
"passcode": "XYZVW",
|
"passcode": "XYZVW",
|
||||||
"server": "rotate.aprs2.net",
|
"server": "rotate.aprs2.net",
|
||||||
"port": 14580,
|
"port": 14580,
|
||||||
"filter": "m/10",
|
"filter": "m/10",
|
||||||
"toRF": false
|
"messagesToRF": false,
|
||||||
|
"objectsToRF": false
|
||||||
|
},
|
||||||
|
"digi": {
|
||||||
|
"mode": 0,
|
||||||
|
"ecoMode": false
|
||||||
},
|
},
|
||||||
"lora": {
|
"lora": {
|
||||||
"txFreq": 433775000,
|
"txFreq": 433775000,
|
||||||
@@ -44,22 +46,56 @@
|
|||||||
"timeout": 4,
|
"timeout": 4,
|
||||||
"turn180": false
|
"turn180": false
|
||||||
},
|
},
|
||||||
|
"battery": {
|
||||||
|
"sendInternalVoltage": false,
|
||||||
|
"monitorInternalVoltage": false,
|
||||||
|
"internalSleepVoltage": 2.9,
|
||||||
|
"sendExternalVoltage": false,
|
||||||
|
"externalVoltagePin": 34,
|
||||||
|
"monitorExternalVoltage": false,
|
||||||
|
"externalSleepVoltage": 10.9,
|
||||||
|
"voltageDividerR1": 100.0,
|
||||||
|
"voltageDividerR2": 27.0,
|
||||||
|
"sendVoltageAsTelemetry": false
|
||||||
|
},
|
||||||
|
"wxsensor": {
|
||||||
|
"active": false,
|
||||||
|
"heightCorrection": 0,
|
||||||
|
"temperatureCorrection": 0.0
|
||||||
|
},
|
||||||
"syslog": {
|
"syslog": {
|
||||||
"active": false,
|
"active": false,
|
||||||
"server": "192.168.0.100",
|
"server": "lora.link9.net",
|
||||||
"port": 514
|
"port": 1514
|
||||||
},
|
},
|
||||||
"bme": {
|
"tnc": {
|
||||||
"active": false
|
"enableServer": false,
|
||||||
|
"enableSerial": false,
|
||||||
|
"acceptOwn": false
|
||||||
},
|
},
|
||||||
"ota": {
|
"ota": {
|
||||||
"username": "",
|
"username": "",
|
||||||
"password": ""
|
"password": ""
|
||||||
},
|
},
|
||||||
|
"webadmin": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": ""
|
||||||
|
},
|
||||||
|
"ntp": {
|
||||||
|
"gmtCorrection": 0.0
|
||||||
|
},
|
||||||
|
"remoteManagement": {
|
||||||
|
"managers": "",
|
||||||
|
"rfOnly": true
|
||||||
|
},
|
||||||
"other": {
|
"other": {
|
||||||
"rememberStationTime": 30,
|
"rememberStationTime": 30,
|
||||||
"sendBatteryVoltage": false,
|
"lowPowerMode": false,
|
||||||
"externalVoltageMeasurement": false,
|
"lowVoltageCutOff": 0,
|
||||||
"externalVoltagePin": 34
|
"backupDigiMode": false,
|
||||||
}
|
"rebootMode": false,
|
||||||
}
|
"rebootModeTime": 6
|
||||||
|
},
|
||||||
|
"personalNote": "",
|
||||||
|
"blacklist": ""
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 813 B |
@@ -74,19 +74,18 @@ logCheckbox.addEventListener("change", function () {
|
|||||||
function loadSettings(settings) {
|
function loadSettings(settings) {
|
||||||
currentSettings = settings;
|
currentSettings = settings;
|
||||||
// General
|
// General
|
||||||
document.getElementById("callsign").value = settings.callsign;
|
document.getElementById("callsign").value = settings.callsign;
|
||||||
// document.getElementById("stationMode").value = settings.stationMode;
|
document.getElementById("beacon.comment").value = settings.beacon.comment;
|
||||||
document.getElementById("bme.active").checked = settings.bme.active;
|
document.getElementById("beacon.path").value = settings.beacon.path;
|
||||||
document.getElementById("beacon.comment").value = settings.beacon.comment;
|
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
|
||||||
document.getElementById("beacon.symbol").value = settings.beacon.symbol;
|
document.getElementById("beacon.overlay").value = settings.beacon.overlay;
|
||||||
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.getElementById("action.symbol").value = settings.beacon.overlay + settings.beacon.symbol;
|
document.querySelector(".list-networks").innerHTML = "";
|
||||||
|
|
||||||
document.querySelector(".list-networks").innerHTML = "";
|
|
||||||
|
|
||||||
// Networks
|
// Networks
|
||||||
const wifiNetworks = settings.wifi.AP;
|
const wifiNetworks = settings.wifi.AP || [];
|
||||||
const networksContainer = document.querySelector(".list-networks");
|
const networksContainer = document.querySelector(".list-networks");
|
||||||
|
|
||||||
let networkCount = 0;
|
let networkCount = 0;
|
||||||
@@ -119,99 +118,145 @@ function loadSettings(settings) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// APRS-IS
|
// APRS-IS
|
||||||
document.getElementById("aprs_is.active").checked = settings.aprs_is.active;
|
document.getElementById("aprs_is.active").checked = settings.aprs_is.active;
|
||||||
document.getElementById("aprs_is.toRF").checked = settings.aprs_is.toRF;
|
document.getElementById("aprs_is.messagesToRF").checked = settings.aprs_is.messagesToRF;
|
||||||
document.getElementById("aprs_is.server").value = settings.aprs_is.server;
|
document.getElementById("aprs_is.objectsToRF").checked = settings.aprs_is.objectsToRF;
|
||||||
document.getElementById("aprs_is.port").value = settings.aprs_is.port;
|
document.getElementById("aprs_is.server").value = settings.aprs_is.server;
|
||||||
document.getElementById("aprs_is.filter").value = settings.aprs_is.filter;
|
document.getElementById("aprs_is.port").value = settings.aprs_is.port;
|
||||||
document.getElementById("aprs_is.passcode").value =
|
document.getElementById("aprs_is.filter").value = settings.aprs_is.filter;
|
||||||
settings.aprs_is.passcode;
|
document.getElementById("aprs_is.passcode").value = settings.aprs_is.passcode;
|
||||||
|
|
||||||
|
// Beacon
|
||||||
|
document.getElementById("beacon.latitude").value = settings.beacon.latitude;
|
||||||
|
document.getElementById("beacon.longitude").value = settings.beacon.longitude;
|
||||||
|
document.getElementById("beacon.interval").value = settings.beacon.interval;
|
||||||
|
document.getElementById("other.rememberStationTime").value = settings.other.rememberStationTime;
|
||||||
|
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;
|
||||||
|
document.getElementById("lora.rxFreq").value = settings.lora.rxFreq;
|
||||||
|
document.getElementById("lora.txActive").checked = settings.lora.txActive;
|
||||||
|
document.getElementById("lora.rxActive").checked = settings.lora.rxActive;
|
||||||
|
document.getElementById("lora.spreadingFactor").value = settings.lora.spreadingFactor;
|
||||||
|
document.getElementById("lora.signalBandwidth").value = settings.lora.signalBandwidth;
|
||||||
|
document.getElementById("lora.codingRate4").value = settings.lora.codingRate4;
|
||||||
|
document.getElementById("lora.power").value = settings.lora.power;
|
||||||
|
|
||||||
// Display
|
// Display
|
||||||
document.getElementById("display.alwaysOn").checked =
|
document.getElementById("display.alwaysOn").checked = settings.display.alwaysOn;
|
||||||
settings.display.alwaysOn;
|
document.getElementById("display.turn180").checked = settings.display.turn180;
|
||||||
document.getElementById("display.turn180").checked =
|
document.getElementById("display.timeout").value = settings.display.timeout;
|
||||||
settings.display.turn180;
|
|
||||||
document.getElementById("display.timeout").value = settings.display.timeout;
|
|
||||||
|
|
||||||
if (settings.display.alwaysOn) {
|
if (settings.display.alwaysOn) {
|
||||||
timeoutInput.disabled = true;
|
timeoutInput.disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WiFi Auto AP
|
// BATTERY
|
||||||
document.getElementById("wifi.autoAP.password").value =
|
document.getElementById("battery.sendInternalVoltage").checked = settings.battery.sendInternalVoltage;
|
||||||
settings.wifi.autoAP.password;
|
document.getElementById("battery.monitorInternalVoltage").checked = settings.battery.monitorInternalVoltage;
|
||||||
document.getElementById("wifi.autoAP.powerOff").value =
|
document.getElementById("battery.internalSleepVoltage").value = settings.battery.internalSleepVoltage.toFixed(1);
|
||||||
settings.wifi.autoAP.powerOff;
|
document.getElementById("battery.sendExternalVoltage").checked = settings.battery.sendExternalVoltage;
|
||||||
|
document.getElementById("battery.externalVoltagePin").value = settings.battery.externalVoltagePin;
|
||||||
// Digi
|
document.getElementById("battery.voltageDividerR1").value = settings.battery.voltageDividerR1.toFixed(1);
|
||||||
// document.getElementById("digi.comment").value = settings.digi.comment;
|
document.getElementById("battery.voltageDividerR2").value = settings.battery.voltageDividerR2.toFixed(1);
|
||||||
// document.getElementById("digi.latitude").value = settings.digi.latitude;
|
document.getElementById("battery.monitorExternalVoltage").checked = settings.battery.monitorExternalVoltage;
|
||||||
// document.getElementById("digi.longitude").value = settings.digi.longitude;
|
document.getElementById("battery.externalSleepVoltage").value = settings.battery.externalSleepVoltage.toFixed(1);
|
||||||
document.getElementById("digi.mode").value = settings.digi.mode;
|
document.getElementById("battery.sendVoltageAsTelemetry").checked = settings.battery.sendVoltageAsTelemetry;
|
||||||
|
|
||||||
// OTA
|
// TELEMETRY WX SENSOR
|
||||||
document.getElementById("ota.username").value = settings.ota.username;
|
document.getElementById("wxsensor.active").checked = settings.wxsensor.active;
|
||||||
document.getElementById("ota.password").value = settings.ota.password;
|
document.getElementById("wxsensor.heightCorrection").value = settings.wxsensor.heightCorrection;
|
||||||
|
document.getElementById("wxsensor.temperatureCorrection").value = settings.wxsensor.temperatureCorrection.toFixed(1);
|
||||||
// Beacon
|
|
||||||
document.getElementById("beacon.interval").value = settings.beacon.interval;
|
// SYSLOG
|
||||||
document.getElementById("other.rememberStationTime").value =
|
document.getElementById("syslog.active").checked = settings.syslog.active;
|
||||||
settings.other.rememberStationTime;
|
document.getElementById("syslog.server").value = settings.syslog.server;
|
||||||
document.getElementById("other.sendBatteryVoltage").checked =
|
document.getElementById("syslog.port").value = settings.syslog.port;
|
||||||
settings.other.sendBatteryVoltage;
|
|
||||||
document.getElementById("other.externalVoltageMeasurement").checked =
|
|
||||||
settings.other.externalVoltageMeasurement;
|
|
||||||
document.getElementById("other.externalVoltagePin").value =
|
|
||||||
settings.other.externalVoltagePin;
|
|
||||||
// document.getElementById("beacon.igateSendsLoRaBeacon").value =
|
|
||||||
// settings.beacon.igateSendsLoRaBeacon;
|
|
||||||
// document.getElementById("beacon.igateRepeatLoRaPackets").value =
|
|
||||||
// settings.beacon.igateRepeatLoRaPackets;
|
|
||||||
document.getElementById("beacon.path").value = settings.beacon.path;
|
|
||||||
document.getElementById("beacon.latitude").value = settings.beacon.latitude;
|
|
||||||
document.getElementById("beacon.longitude").value =
|
|
||||||
settings.beacon.longitude;
|
|
||||||
document.getElementById("beacon.sendViaAPRSIS").checked =
|
|
||||||
settings.beacon.sendViaAPRSIS;
|
|
||||||
document.getElementById("beacon.sendViaRF").checked =
|
|
||||||
settings.beacon.sendViaRF;
|
|
||||||
|
|
||||||
// Syslog
|
|
||||||
document.getElementById("syslog.active").checked = settings.syslog.active;
|
|
||||||
document.getElementById("syslog.server").value = settings.syslog.server;
|
|
||||||
document.getElementById("syslog.port").value = settings.syslog.port;
|
|
||||||
|
|
||||||
if (settings.syslog.active) {
|
if (settings.syslog.active) {
|
||||||
serverField.disabled = false;
|
serverField.disabled = false;
|
||||||
portField.disabled = false;
|
portField.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoRa
|
// TNC
|
||||||
// document.getElementById("lora.digirepeaterTxFreq").value =
|
if (settings.tnc) {
|
||||||
// settings.lora.digirepeaterTxFreq;
|
document.getElementById("tnc.enableServer").checked = settings.tnc.enableServer;
|
||||||
// document.getElementById("lora.iGateFreq").value = settings.lora.iGateFreq;
|
document.getElementById("tnc.enableSerial").checked = settings.tnc.enableSerial;
|
||||||
// document.getElementById("lora.digirepeaterRxFreq").value =
|
document.getElementById("tnc.acceptOwn").checked = settings.tnc.acceptOwn;
|
||||||
// settings.lora.digirepeaterRxFreq;
|
}
|
||||||
document.getElementById("lora.txFreq").value = settings.lora.txFreq;
|
|
||||||
document.getElementById("lora.rxFreq").value = settings.lora.rxFreq;
|
// Reboot
|
||||||
document.getElementById("lora.txActive").checked = settings.lora.txActive;
|
document.getElementById("other.rebootMode").checked = settings.other.rebootMode;
|
||||||
document.getElementById("lora.rxActive").checked = settings.lora.rxActive;
|
document.getElementById("other.rebootModeTime").value = settings.other.rebootModeTime;
|
||||||
document.getElementById("lora.spreadingFactor").value =
|
|
||||||
settings.lora.spreadingFactor;
|
// WiFi Auto AP
|
||||||
document.getElementById("lora.signalBandwidth").value =
|
document.getElementById("wifi.autoAP.password").value = settings.wifi.autoAP.password;
|
||||||
settings.lora.signalBandwidth;
|
document.getElementById("wifi.autoAP.timeout").value = settings.wifi.autoAP.timeout;
|
||||||
document.getElementById("lora.codingRate4").value =
|
|
||||||
settings.lora.codingRate4;
|
// OTA
|
||||||
document.getElementById("lora.power").value = settings.lora.power;
|
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();
|
updateImage();
|
||||||
refreshSpeedStandard();
|
refreshSpeedStandard();
|
||||||
|
toggleFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
const bmeCheckbox = document.querySelector("input[name='bme.active']");
|
function showToast(message) {
|
||||||
|
const el = document.querySelector('#toast');
|
||||||
|
|
||||||
const stationModeSelect = document.querySelector("select[name='stationMode']");
|
el.querySelector('.toast-body').innerHTML = message;
|
||||||
|
|
||||||
|
(new bootstrap.Toast(el)).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('send-beacon').addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
fetch("/action?type=send-beacon", { method: "POST" });
|
||||||
|
|
||||||
|
showToast("Your beacon will be sent in a moment. <br> <u>This action will be ignored if you have APRSIS and LoRa TX disabled!</u>");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('reboot').addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
fetch("/action?type=reboot", { method: "POST" });
|
||||||
|
|
||||||
|
showToast("Your device will be rebooted in a while");
|
||||||
|
});
|
||||||
|
|
||||||
|
const wxsensorCheckbox = document.querySelector("input[name='wxsensor.active']");
|
||||||
|
|
||||||
function updateImage() {
|
function updateImage() {
|
||||||
const value = document.getElementById("beacon.overlay").value + document.getElementById("beacon.symbol").value;
|
const value = document.getElementById("beacon.overlay").value + document.getElementById("beacon.symbol").value;
|
||||||
@@ -239,36 +284,67 @@ function updateImage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleFields() {
|
function toggleFields() {
|
||||||
const sendBatteryVoltageCheckbox = document.querySelector(
|
const sendExternalVoltageCheckbox = document.querySelector(
|
||||||
'input[name="other.sendBatteryVoltage"]'
|
'input[name="battery.sendExternalVoltage"]'
|
||||||
);
|
|
||||||
const externalVoltageMeasurementCheckbox = document.querySelector(
|
|
||||||
'input[name="other.externalVoltageMeasurement"]'
|
|
||||||
);
|
);
|
||||||
const externalVoltagePinInput = document.querySelector(
|
const externalVoltagePinInput = document.querySelector(
|
||||||
'input[name="other.externalVoltagePin"]'
|
'input[name="battery.externalVoltagePin"]'
|
||||||
);
|
);
|
||||||
|
|
||||||
externalVoltageMeasurementCheckbox.disabled =
|
externalVoltagePinInput.disabled = !sendExternalVoltageCheckbox.checked;
|
||||||
!sendBatteryVoltageCheckbox.checked;
|
voltageDividerR1.disabled = !sendExternalVoltageCheckbox.checked;
|
||||||
externalVoltagePinInput.disabled =
|
voltageDividerR2.disabled = !sendExternalVoltageCheckbox.checked;
|
||||||
!externalVoltageMeasurementCheckbox.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 sendBatteryVoltageCheckbox = document.querySelector(
|
const sendExternalVoltageCheckbox = document.querySelector(
|
||||||
'input[name="other.sendBatteryVoltage"]'
|
'input[name="battery.sendExternalVoltage"]'
|
||||||
);
|
|
||||||
const externalVoltageMeasurementCheckbox = document.querySelector(
|
|
||||||
'input[name="other.externalVoltageMeasurement"]'
|
|
||||||
);
|
);
|
||||||
const externalVoltagePinInput = document.querySelector(
|
const externalVoltagePinInput = document.querySelector(
|
||||||
'input[name="other.externalVoltagePin"]'
|
'input[name="battery.externalVoltagePin"]'
|
||||||
);
|
);
|
||||||
|
|
||||||
sendBatteryVoltageCheckbox.addEventListener("change", function () {
|
const voltageDividerR1 = document.querySelector(
|
||||||
externalVoltageMeasurementCheckbox.disabled = !this.checked;
|
'input[name="battery.voltageDividerR1"]'
|
||||||
externalVoltagePinInput.disabled =
|
);
|
||||||
!externalVoltageMeasurementCheckbox.checked;
|
|
||||||
|
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 () {
|
document.querySelector(".new button").addEventListener("click", function () {
|
||||||
@@ -378,8 +454,6 @@ document.getElementById("action.speed").addEventListener("change", function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
toggleFields();
|
|
||||||
|
|
||||||
const form = document.querySelector("form");
|
const form = document.querySelector("form");
|
||||||
|
|
||||||
const saveModal = new bootstrap.Modal(document.getElementById("saveModal"), {
|
const saveModal = new bootstrap.Modal(document.getElementById("saveModal"), {
|
||||||
@@ -431,3 +505,54 @@ form.addEventListener("submit", async (event) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fetchSettings();
|
fetchSettings();
|
||||||
|
|
||||||
|
function loadReceivedPackets(packets) {
|
||||||
|
if (packets) {
|
||||||
|
document.querySelector('#received-packets tbody').innerHTML = '';
|
||||||
|
|
||||||
|
const container = document.querySelector("#received-packets tbody");
|
||||||
|
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
const date = new Date();
|
||||||
|
|
||||||
|
packets.forEach((packet) => {
|
||||||
|
const element = document.createElement("tr");
|
||||||
|
|
||||||
|
element.innerHTML = `
|
||||||
|
<td>${packet.rxTime}</td>
|
||||||
|
<td>${packet.packet}</td>
|
||||||
|
<td>${packet.RSSI}</td>
|
||||||
|
<td>${packet.SNR}</td>
|
||||||
|
`;
|
||||||
|
|
||||||
|
container.appendChild(element);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(fetchReceivedPackets, 15000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchReceivedPackets() {
|
||||||
|
fetch("/received-packets.json")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((packets) => {
|
||||||
|
loadReceivedPackets(packets);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
|
||||||
|
console.error(`Failed to load received packets`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('a[href="/received-packets"]').addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
document.getElementById('received-packets').classList.remove('d-none');
|
||||||
|
document.getElementById('configuration').classList.add('d-none');
|
||||||
|
|
||||||
|
document.querySelector('button[type=submit]').remove();
|
||||||
|
|
||||||
|
fetchReceivedPackets();
|
||||||
|
})
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.alert-fixed {
|
||||||
|
position:fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
z-index:9999;
|
||||||
|
border-radius:0px
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 527 KiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 150 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 624 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef A7670_UTILS_H_
|
||||||
|
#define A7670_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace A7670_Utils {
|
||||||
|
|
||||||
|
bool checkModemOn();
|
||||||
|
void setup();
|
||||||
|
bool checkATResponse(const String& ATMessage);
|
||||||
|
void APRS_IS_connect();
|
||||||
|
void uploadToAPRSIS(const String& packet);
|
||||||
|
void listenAPRSIS();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ifndef APRS_IS_UTILS_H_
|
||||||
|
#define APRS_IS_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace APRS_IS_Utils {
|
||||||
|
|
||||||
|
void upload(const String& line);
|
||||||
|
void connect();
|
||||||
|
|
||||||
|
void checkStatus();
|
||||||
|
String checkForStartingBytes(const String& packet);
|
||||||
|
|
||||||
|
String buildPacketToUpload(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
|
||||||
@@ -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 checkIfShouldSleep(); // ????
|
||||||
|
void startupBatteryHealth();
|
||||||
|
|
||||||
|
String generateEncodedTelemetryBytes(float value, bool firstBytes, byte voltageType);
|
||||||
|
String generateEncodedTelemetry();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#ifndef CONFIGURATION_H_
|
||||||
|
#define CONFIGURATION_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
|
||||||
|
class WiFi_AP {
|
||||||
|
public:
|
||||||
|
String ssid;
|
||||||
|
String password;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WiFi_Auto_AP {
|
||||||
|
public:
|
||||||
|
String password;
|
||||||
|
int timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BEACON {
|
||||||
|
public:
|
||||||
|
double latitude;
|
||||||
|
double longitude;
|
||||||
|
String comment;
|
||||||
|
int interval;
|
||||||
|
String overlay;
|
||||||
|
String symbol;
|
||||||
|
String path;
|
||||||
|
bool sendViaRF;
|
||||||
|
bool sendViaAPRSIS;
|
||||||
|
bool gpsActive;
|
||||||
|
bool gpsAmbiguity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class APRS_IS {
|
||||||
|
public:
|
||||||
|
bool active;
|
||||||
|
String passcode;
|
||||||
|
String server;
|
||||||
|
int port;
|
||||||
|
String filter;
|
||||||
|
bool messagesToRF;
|
||||||
|
bool objectsToRF;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DIGI {
|
||||||
|
public:
|
||||||
|
int mode;
|
||||||
|
bool ecoMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoraModule {
|
||||||
|
public:
|
||||||
|
long txFreq;
|
||||||
|
long rxFreq;
|
||||||
|
bool txActive;
|
||||||
|
bool rxActive;
|
||||||
|
int spreadingFactor;
|
||||||
|
long signalBandwidth;
|
||||||
|
int codingRate4;
|
||||||
|
int power;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Display {
|
||||||
|
public:
|
||||||
|
bool alwaysOn;
|
||||||
|
int timeout;
|
||||||
|
bool turn180;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BATTERY {
|
||||||
|
public:
|
||||||
|
bool sendInternalVoltage;
|
||||||
|
bool monitorInternalVoltage;
|
||||||
|
float internalSleepVoltage;
|
||||||
|
bool sendExternalVoltage;
|
||||||
|
int externalVoltagePin;
|
||||||
|
bool monitorExternalVoltage;
|
||||||
|
float externalSleepVoltage;
|
||||||
|
float voltageDividerR1;
|
||||||
|
float voltageDividerR2;
|
||||||
|
bool sendVoltageAsTelemetry;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WXSENSOR {
|
||||||
|
public:
|
||||||
|
bool active;
|
||||||
|
int heightCorrection;
|
||||||
|
float temperatureCorrection;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SYSLOG {
|
||||||
|
public:
|
||||||
|
bool active;
|
||||||
|
String server;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TNC {
|
||||||
|
public:
|
||||||
|
bool enableServer;
|
||||||
|
bool enableSerial;
|
||||||
|
bool acceptOwn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OTA {
|
||||||
|
public:
|
||||||
|
String username;
|
||||||
|
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:
|
||||||
|
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;
|
||||||
|
APRS_IS aprs_is;
|
||||||
|
DIGI digi;
|
||||||
|
LoraModule loramodule;
|
||||||
|
Display display;
|
||||||
|
BATTERY battery;
|
||||||
|
WXSENSOR wxsensor;
|
||||||
|
SYSLOG syslog;
|
||||||
|
TNC tnc;
|
||||||
|
OTA ota;
|
||||||
|
WEBADMIN webadmin;
|
||||||
|
NTP ntp;
|
||||||
|
REMOTE_MANAGEMENT remoteManagement;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void writeFile();
|
||||||
|
Configuration();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool readFile();
|
||||||
|
String _filePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef DIGI_UTILS_H_
|
||||||
|
#define DIGI_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DIGI_Utils {
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef GPS_UTILS_H_
|
||||||
|
#define GPS_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace GPS_Utils {
|
||||||
|
|
||||||
|
String getiGateLoRaBeaconPacket();
|
||||||
|
char *ax25_base91enc(char *s, uint8_t n, uint32_t v);
|
||||||
|
String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol);
|
||||||
|
void generateBeaconFirstPart();
|
||||||
|
void generateBeacons();
|
||||||
|
String decodeEncodedGPS(const String& packet);
|
||||||
|
String getReceivedGPS(const String& packet);
|
||||||
|
String getDistanceAndComment(const String& packet);
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void getData();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#define DCD_ON 0x03
|
||||||
|
|
||||||
|
#define FEND 0xC0
|
||||||
|
#define FESC 0xDB
|
||||||
|
#define TFEND 0xDC
|
||||||
|
#define TFESC 0xDD
|
||||||
|
|
||||||
|
#define CMD_UNKNOWN 0xFE
|
||||||
|
#define CMD_DATA 0x00
|
||||||
|
#define CMD_HARDWARE 0x06
|
||||||
|
|
||||||
|
#define HW_RSSI 0x21
|
||||||
|
|
||||||
|
#define CMD_ERROR 0x90
|
||||||
|
#define ERROR_INITRADIO 0x01
|
||||||
|
#define ERROR_TXFAILED 0x02
|
||||||
|
#define ERROR_QUEUE_FULL 0x04
|
||||||
|
|
||||||
|
#define APRS_CONTROL_FIELD 0x03
|
||||||
|
#define APRS_INFORMATION_FIELD 0xf0
|
||||||
|
|
||||||
|
#define HAS_BEEN_DIGIPITED_MASK 0b10000000
|
||||||
|
#define IS_LAST_ADDRESS_POSITION_MASK 0b1
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef KISS_UTILS_H_
|
||||||
|
#define KISS_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
String encodeAddressAX25(String tnc2Address);
|
||||||
|
String decodeAddressAX25(const String& ax25Address, bool& isLast, bool isRelay);
|
||||||
|
|
||||||
|
String encapsulateKISS(const String& ax25Frame, uint8_t cmd);
|
||||||
|
String decapsulateKISS(const String& frame);
|
||||||
|
|
||||||
|
String encodeKISS(const String& frame);
|
||||||
|
String decodeKISS(const String& inputFrame, bool& dataFrame);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef LORA_UTILS_H_
|
||||||
|
#define LORA_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace LoRa_Utils {
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void sendNewPacket(const String& newPacket);
|
||||||
|
//String packetSanitization(const String& packet);
|
||||||
|
String receivePacket();
|
||||||
|
void changeFreqTx();
|
||||||
|
void changeFreqRx();
|
||||||
|
void startReceive();
|
||||||
|
void sleepRadio();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef POWER_UTILS_H_
|
||||||
|
#define POWER_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
|
#include "XPowersLib.h"
|
||||||
|
#else
|
||||||
|
#include <Wire.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace POWER_Utils {
|
||||||
|
|
||||||
|
double getBatteryVoltage();
|
||||||
|
bool isBatteryConnected();
|
||||||
|
void activateMeasurement();
|
||||||
|
void activateGPS();
|
||||||
|
void deactivateGPS();
|
||||||
|
void activateLoRa();
|
||||||
|
void deactivateLoRa();
|
||||||
|
bool begin(TwoWire &port);
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -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 loadBlacklist();
|
||||||
|
void loadManagers();
|
||||||
|
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 processOutputPacketBuffer();
|
||||||
|
void addToOutputPacketBuffer(const String& packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef SYSLOG_H_
|
||||||
|
#define SYSLOG_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace SYSLOG_Utils {
|
||||||
|
|
||||||
|
void log(const uint8_t type ,const String& packet, const int rssi, const float snr, const int freqError);
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef TNC_UTILS_H_
|
||||||
|
#define TNC_UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace TNC_Utils {
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
void sendToClients(const String& packet);
|
||||||
|
void sendToSerial(const String& packet);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef UTILS_H_
|
||||||
|
#define UTILS_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
|
||||||
|
class ReceivedPacket {
|
||||||
|
public:
|
||||||
|
String rxTime;
|
||||||
|
String packet;
|
||||||
|
int RSSI;
|
||||||
|
float SNR;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
void processStatus();
|
||||||
|
String getLocalIP();
|
||||||
|
void setupDisplay();
|
||||||
|
void activeStations();
|
||||||
|
void checkBeaconInterval();
|
||||||
|
void checkDisplayInterval();
|
||||||
|
void validateFreqs();
|
||||||
|
void typeOfPacket(const String& packet, const uint8_t packetType);
|
||||||
|
void print(const String& text);
|
||||||
|
void println(const String& text);
|
||||||
|
void checkRebootMode();
|
||||||
|
void checkRebootTime();
|
||||||
|
void checkSleepByLowBatteryVoltage(uint8_t mode);
|
||||||
|
bool checkValidCallsign(const String& callsign);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -13,10 +13,6 @@ namespace WEB_Utils {
|
|||||||
void handleNotFound(AsyncWebServerRequest *request);
|
void handleNotFound(AsyncWebServerRequest *request);
|
||||||
void handleStatus(AsyncWebServerRequest *request);
|
void handleStatus(AsyncWebServerRequest *request);
|
||||||
void handleHome(AsyncWebServerRequest *request);
|
void handleHome(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
//void handleReadConfiguration(AsyncWebServerRequest *request);
|
|
||||||
//void handleWriteConfiguration(AsyncWebServerRequest *request);
|
|
||||||
|
|
||||||
void handleStyle(AsyncWebServerRequest *request);
|
void handleStyle(AsyncWebServerRequest *request);
|
||||||
void handleScript(AsyncWebServerRequest *request);
|
void handleScript(AsyncWebServerRequest *request);
|
||||||
void handleBootstrapStyle(AsyncWebServerRequest *request);
|
void handleBootstrapStyle(AsyncWebServerRequest *request);
|
||||||
@@ -9,7 +9,7 @@ namespace WIFI_Utils {
|
|||||||
void checkWiFi();
|
void checkWiFi();
|
||||||
void startAutoAP();
|
void startAutoAP();
|
||||||
void startWiFi();
|
void startWiFi();
|
||||||
void checkIfAutoAPShouldPowerOff();
|
void checkAutoAPTimeout();
|
||||||
void setup();
|
void setup();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -11,8 +11,13 @@
|
|||||||
[platformio]
|
[platformio]
|
||||||
default_envs = ttgo-lora32-v21
|
default_envs = ttgo-lora32-v21
|
||||||
|
|
||||||
|
extra_configs =
|
||||||
|
common_settings.ini
|
||||||
|
variants/*/platformio.ini
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
platform = espressif32 @ 6.3.1
|
platform = espressif32 @ 6.7.0
|
||||||
|
board_build.partitions = min_spiffs.csv
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
board_build.embed_files =
|
board_build.embed_files =
|
||||||
@@ -21,67 +26,7 @@ board_build.embed_files =
|
|||||||
data_embed/script.js.gz
|
data_embed/script.js.gz
|
||||||
data_embed/bootstrap.css.gz
|
data_embed/bootstrap.css.gz
|
||||||
data_embed/bootstrap.js.gz
|
data_embed/bootstrap.js.gz
|
||||||
lib_deps =
|
data_embed/favicon.png.gz
|
||||||
bblanchon/ArduinoJson@^6.20.2
|
|
||||||
sandeepmistry/LoRa@^0.8.0
|
|
||||||
adafruit/Adafruit GFX Library @ 1.11.5
|
|
||||||
adafruit/Adafruit SSD1306 @ 2.5.7
|
|
||||||
mikalhart/TinyGPSPlus @ 1.0.3
|
|
||||||
adafruit/Adafruit Unified Sensor@^1.1.9
|
|
||||||
adafruit/Adafruit BME280 Library@^2.2.2
|
|
||||||
adafruit/Adafruit BMP280 Library@^2.6.8
|
|
||||||
adafruit/Adafruit BME680 Library@^2.0.4
|
|
||||||
jgromes/RadioLib @ 6.1.0
|
|
||||||
lewisxhe/XPowersLib@^0.1.8
|
|
||||||
ayushsharma82/ElegantOTA@^3.1.0
|
|
||||||
ottowinter/ESPAsyncWebServer-esphome@3.0.0
|
|
||||||
esphome/AsyncTCP-esphome@2.1.1
|
|
||||||
|
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
pre:tools/compress.py
|
pre:tools/compress.py
|
||||||
|
debug_tool = esp-prog
|
||||||
debug_tool = esp-prog
|
|
||||||
|
|
||||||
[env:ttgo-lora32-v21]
|
|
||||||
board = ttgo-lora32-v21
|
|
||||||
build_flags = -Werror -Wall -DTTGO_T_LORA32_V2_1 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:heltec-lora32-v2]
|
|
||||||
board = ttgo-lora32-v21
|
|
||||||
build_flags = -Werror -Wall -DHELTEC_V2 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:heltec_wifi_lora_32_V3]
|
|
||||||
board = heltec_wifi_lora_32_V3
|
|
||||||
build_flags = -Werror -Wall -DHELTEC_V3 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
board_build.mcu = esp32s3
|
|
||||||
|
|
||||||
[env:ESP32_DIY_LoRa]
|
|
||||||
board = esp32dev
|
|
||||||
build_flags = -Werror -Wall -DESP32_DIY_LoRa -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:ESP32_DIY_1W_LoRa]
|
|
||||||
board = esp32dev
|
|
||||||
build_flags = -Werror -Wall -DESP32_DIY_1W_LoRa -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:ttgo-t-beam-v1_2]
|
|
||||||
board = ttgo-t-beam
|
|
||||||
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_2 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:ttgo-t-beam-v1]
|
|
||||||
board = ttgo-t-beam
|
|
||||||
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_0 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:ttgo-t-beam-v1_SX1268]
|
|
||||||
board = ttgo-t-beam
|
|
||||||
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_0_SX1268 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:ttgo-t-beam-v1_2_SX1262]
|
|
||||||
board = ttgo-t-beam
|
|
||||||
build_flags = -Werror -Wall -DTTGO_T_Beam_V1_2_SX1262 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
|
|
||||||
[env:heltec_wireless_stick_lite]
|
|
||||||
platform = espressif32
|
|
||||||
board = heltec_wireless_stick_lite
|
|
||||||
board_build.mcu = esp32c3
|
|
||||||
board_build.f_cpu = 240000000L
|
|
||||||
build_flags = -Werror -Wall -DHELTEC_CT62 -DELEGANTOTA_USE_ASYNC_WEBSERVER=1
|
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
#include "aprs_is_utils.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
|
||||||
|
#define SerialAT Serial1
|
||||||
|
#include <TinyGsmClient.h>
|
||||||
|
#include <StreamDebugger.h>
|
||||||
|
StreamDebugger debugger(SerialAT, Serial);
|
||||||
|
TinyGsm modem(debugger);
|
||||||
|
|
||||||
|
extern Configuration Config;
|
||||||
|
extern String firstLine;
|
||||||
|
|
||||||
|
bool modemStartUp = false;
|
||||||
|
bool serverStartUp = false;
|
||||||
|
bool userBytesSended = false;
|
||||||
|
bool beaconBytesSended = false;
|
||||||
|
bool beaconSended = false;
|
||||||
|
bool stationBeacon = false;
|
||||||
|
|
||||||
|
extern bool modemLoggedToAPRSIS;
|
||||||
|
|
||||||
|
|
||||||
|
namespace A7670_Utils {
|
||||||
|
|
||||||
|
bool checkModemOn() {
|
||||||
|
bool modemReady = false;
|
||||||
|
Serial.print("Starting Modem ... ");
|
||||||
|
displayShow(firstLine, "Starting Modem...", " ", " ", 0);
|
||||||
|
|
||||||
|
pinMode(A7670_ResetPin, OUTPUT); //A7670 Reset
|
||||||
|
digitalWrite(A7670_ResetPin, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(A7670_ResetPin, HIGH);
|
||||||
|
delay(3000);
|
||||||
|
digitalWrite(A7670_ResetPin, LOW);
|
||||||
|
|
||||||
|
pinMode(A7670_PWR_PIN, OUTPUT);
|
||||||
|
digitalWrite(A7670_PWR_PIN, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(A7670_PWR_PIN, HIGH);
|
||||||
|
delay(1000);
|
||||||
|
digitalWrite(A7670_PWR_PIN, LOW);
|
||||||
|
|
||||||
|
int i = 20;
|
||||||
|
while (i) {
|
||||||
|
SerialAT.println("AT");
|
||||||
|
delay(500);
|
||||||
|
if (SerialAT.available()) {
|
||||||
|
String r = SerialAT.readString();
|
||||||
|
//Serial.println(r);
|
||||||
|
if ( r.indexOf("OK") >= 0 ) {
|
||||||
|
modemReady = true;
|
||||||
|
i = 1;
|
||||||
|
Serial.println("Modem Ready!\n");
|
||||||
|
displayShow(firstLine, "Starting Modem...", "---> Modem Ready", " ", 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!modemReady) {
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
SerialAT.begin(115200, SERIAL_8N1, A7670_RX_PIN, A7670_TX_PIN);
|
||||||
|
if (checkModemOn()) {;
|
||||||
|
delay(1000);
|
||||||
|
//setup_gps(); // if gps active / won't be need for now
|
||||||
|
} else {
|
||||||
|
displayShow(firstLine, "Starting Modem...", "---> Failed !!!", " ", 0);
|
||||||
|
Serial.println(F("*********** Failed to connect to the modem! ***********"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkATResponse(const String& ATMessage) {
|
||||||
|
int delayATMessage = 3000;
|
||||||
|
bool validAT = false;
|
||||||
|
//Serial.println(ATMessage);
|
||||||
|
int i = 10;
|
||||||
|
while (i) {
|
||||||
|
if (!validAT) {
|
||||||
|
SerialAT.println(ATMessage);
|
||||||
|
}
|
||||||
|
delay(500);
|
||||||
|
if (SerialAT.available()) {
|
||||||
|
String response = SerialAT.readString();
|
||||||
|
//Serial.println(response); // DEBUG of Modem AT message
|
||||||
|
if(response.indexOf("verified") >= 0) {
|
||||||
|
Serial.println("Logged! (User Validated)\n");
|
||||||
|
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!");
|
||||||
|
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)");
|
||||||
|
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!");
|
||||||
|
displayShow(firstLine, "Connecting APRS-IS...", "---> Contacted", " ", 0);
|
||||||
|
validAT = true;
|
||||||
|
i = 1;
|
||||||
|
delayATMessage = 0;
|
||||||
|
} else if (ATMessage.indexOf("AT+CIPSEND=0,") == 0 && response.indexOf(">") >= 0) {
|
||||||
|
Serial.print(".");
|
||||||
|
validAT = true;
|
||||||
|
i = 1;
|
||||||
|
delayATMessage = 0;
|
||||||
|
} else if (ATMessage.indexOf(Config.callsign) >= 3 && !modemLoggedToAPRSIS && response.indexOf("OK") >= 0 && !stationBeacon) { // login info
|
||||||
|
validAT = true;
|
||||||
|
delayATMessage = 0;
|
||||||
|
} else if (ATMessage.indexOf(Config.callsign) == 0 && !beaconSended && response.indexOf("OK") >= 0 && !stationBeacon) { // self beacon or querys
|
||||||
|
validAT = true;
|
||||||
|
i = 1;
|
||||||
|
delayATMessage = 0;
|
||||||
|
} else if (stationBeacon && response.indexOf("OK") >= 0) { //upload others beacons
|
||||||
|
validAT = true;
|
||||||
|
i = 1;
|
||||||
|
delayATMessage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(delayATMessage);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return validAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void APRS_IS_connect() {
|
||||||
|
String loginInfo = "user ";
|
||||||
|
loginInfo += Config.callsign;
|
||||||
|
loginInfo += " pass ";
|
||||||
|
loginInfo += String(Config.aprs_is.passcode);
|
||||||
|
loginInfo += " vers CA2RXU_LoRa_iGate 1.3 filter ";
|
||||||
|
loginInfo += Config.aprs_is.filter;
|
||||||
|
Serial.println("-----> Connecting to APRS IS");
|
||||||
|
while (!modemStartUp) {
|
||||||
|
Serial.print("Opening Port... ");
|
||||||
|
displayShow(firstLine, "Opening Port...", " ", " ", 0);
|
||||||
|
modemStartUp = checkATResponse("AT+NETOPEN");
|
||||||
|
delay(2000);
|
||||||
|
} while (!serverStartUp) {
|
||||||
|
Serial.print("Connecting APRS-IS Server... ");
|
||||||
|
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 ");
|
||||||
|
displayShow(firstLine, "Connecting APRS-IS...", "---> User Login Data", " ", 0);
|
||||||
|
userBytesSended = checkATResponse("AT+CIPSEND=0," + String(loginInfo.length()+1));
|
||||||
|
delay(2000);
|
||||||
|
} while (!modemLoggedToAPRSIS) {
|
||||||
|
Serial.print(".");
|
||||||
|
modemLoggedToAPRSIS = checkATResponse(loginInfo);
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uploadToAPRSIS(const String& packet) {
|
||||||
|
beaconBytesSended = checkATResponse("AT+CIPSEND=0," + String(packet.length()+1));
|
||||||
|
delay(2000);
|
||||||
|
if (beaconBytesSended) {
|
||||||
|
Serial.print(".");
|
||||||
|
beaconSended = checkATResponse(packet);
|
||||||
|
}
|
||||||
|
if (!beaconSended) {
|
||||||
|
Serial.println("------------------------------------> UPLOAD FAILED!!!");
|
||||||
|
} else {
|
||||||
|
Serial.println("Packet Uploaded to APRS-IS!");
|
||||||
|
}
|
||||||
|
beaconBytesSended = false;
|
||||||
|
beaconSended = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listenAPRSIS() {
|
||||||
|
if (SerialAT.available()) {
|
||||||
|
String packetAPRSIS = SerialAT.readStringUntil('\r');
|
||||||
|
packetAPRSIS.trim();
|
||||||
|
if (!packetAPRSIS.startsWith("#") && packetAPRSIS.indexOf("+IPD") == -1 && packetAPRSIS.indexOf("RECV") == -1 && packetAPRSIS.length() > 0) {
|
||||||
|
APRS_IS_Utils::processAPRSISPacket(packetAPRSIS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,124 +1,242 @@
|
|||||||
|
/*___________________________________________________________________
|
||||||
|
|
||||||
|
██╗ ██████╗ ██████╗ █████╗ █████╗ ██████╗ ██████╗ ███████╗
|
||||||
|
██║ ██╔═══██╗██╔══██╗██╔══██╗ ██╔══██╗██╔══██╗██╔══██╗██╔════╝
|
||||||
|
██║ ██║ ██║██████╔╝███████║ ███████║██████╔╝██████╔╝███████╗
|
||||||
|
██║ ██║ ██║██╔══██╗██╔══██║ ██╔══██║██╔═══╝ ██╔══██╗╚════██║
|
||||||
|
███████╗╚██████╔╝██║ ██║██║ ██║ ██║ ██║██║ ██║ ██║███████║
|
||||||
|
╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝╚══════╝
|
||||||
|
|
||||||
|
██╗ ██████╗ █████╗ ████████╗███████╗
|
||||||
|
██║██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝
|
||||||
|
██║██║ ███╗███████║ ██║ █████╗
|
||||||
|
██║██║ ██║██╔══██║ ██║ ██╔══╝
|
||||||
|
██║╚██████╔╝██║ ██║ ██║ ███████╗
|
||||||
|
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
|
||||||
|
|
||||||
|
|
||||||
|
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 <Arduino.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "aprs_is_utils.h"
|
#include "aprs_is_utils.h"
|
||||||
#include "station_utils.h"
|
#include "station_utils.h"
|
||||||
|
#include "battery_utils.h"
|
||||||
|
#include "board_pinout.h"
|
||||||
#include "syslog_utils.h"
|
#include "syslog_utils.h"
|
||||||
#include "pins_config.h"
|
|
||||||
#include "query_utils.h"
|
|
||||||
#include "power_utils.h"
|
#include "power_utils.h"
|
||||||
#include "lora_utils.h"
|
#include "lora_utils.h"
|
||||||
#include "wifi_utils.h"
|
#include "wifi_utils.h"
|
||||||
#include "digi_utils.h"
|
#include "digi_utils.h"
|
||||||
#include "gps_utils.h"
|
#include "gps_utils.h"
|
||||||
#include "bme_utils.h"
|
|
||||||
#include "web_utils.h"
|
#include "web_utils.h"
|
||||||
|
#include "tnc_utils.h"
|
||||||
|
#include "ntp_utils.h"
|
||||||
|
#include "wx_utils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <ElegantOTA.h>
|
#ifdef HAS_A7670
|
||||||
|
#include "A7670_utils.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Configuration Config;
|
String versionDate = "2025.03.20";
|
||||||
WiFiClient espClient;
|
Configuration Config;
|
||||||
|
WiFiClient espClient;
|
||||||
|
#ifdef HAS_GPS
|
||||||
|
HardwareSerial gpsSerial(1);
|
||||||
|
TinyGPSPlus gps;
|
||||||
|
uint32_t gpsSatelliteTime = 0;
|
||||||
|
bool gpsInfoToggle = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
String versionDate = "2024.03.08";
|
uint8_t myWiFiAPIndex = 0;
|
||||||
int myWiFiAPIndex = 0;
|
int myWiFiAPSize = Config.wifiAPs.size();
|
||||||
int myWiFiAPSize = Config.wifiAPs.size();
|
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
|
||||||
WiFi_AP *currentWiFi = &Config.wifiAPs[myWiFiAPIndex];
|
|
||||||
|
|
||||||
bool isUpdatingOTA = false;
|
bool isUpdatingOTA = false;
|
||||||
bool statusAfterBoot = true;
|
uint32_t lastBatteryCheck = 0;
|
||||||
bool beaconUpdate = true;
|
|
||||||
uint32_t lastBeaconTx = 0;
|
|
||||||
uint32_t previousWiFiMillis = 0;
|
|
||||||
uint32_t lastScreenOn = millis();
|
|
||||||
|
|
||||||
uint32_t lastWiFiCheck = 0;
|
bool backUpDigiMode = false;
|
||||||
bool WiFiConnect = true;
|
bool modemLoggedToAPRSIS = false;
|
||||||
bool WiFiConnected = false;
|
|
||||||
|
|
||||||
bool WiFiAutoAPStarted = false;
|
#ifdef HAS_EPAPER
|
||||||
long WiFiAutoAPTime = false;
|
uint32_t lastEpaperTime = 0;
|
||||||
|
extern String lastEpaperText;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t bmeLastReading = -60000;
|
std::vector<ReceivedPacket> receivedPackets;
|
||||||
|
|
||||||
String batteryVoltage;
|
String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine;
|
||||||
|
//#define STARTUP_DELAY 5 //min
|
||||||
|
|
||||||
std::vector<String> lastHeardStation;
|
|
||||||
std::vector<String> lastHeardStation_temp;
|
|
||||||
std::vector<String> packetBuffer;
|
|
||||||
std::vector<String> packetBuffer_temp;
|
|
||||||
|
|
||||||
String firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, iGateBeaconPacket, iGateLoRaBeaconPacket;
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
|
|
||||||
pinMode(batteryPin, INPUT);
|
|
||||||
#endif
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(HELTEC_V3) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
|
|
||||||
pinMode(internalLedPin, OUTPUT);
|
|
||||||
#endif
|
|
||||||
if (Config.externalVoltageMeasurement) {
|
|
||||||
pinMode(Config.externalVoltagePin, INPUT);
|
|
||||||
}
|
|
||||||
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2) || defined(TTGO_T_Beam_V1_2_SX1262)
|
|
||||||
POWER_Utils::setup();
|
POWER_Utils::setup();
|
||||||
#endif
|
|
||||||
delay(1000);
|
|
||||||
Utils::setupDisplay();
|
Utils::setupDisplay();
|
||||||
|
|
||||||
Config.check();
|
|
||||||
|
|
||||||
WIFI_Utils::setup();
|
|
||||||
LoRa_Utils::setup();
|
LoRa_Utils::setup();
|
||||||
Utils::validateFreqs();
|
Utils::validateFreqs();
|
||||||
|
GPS_Utils::setup();
|
||||||
|
STATION_Utils::loadBlacklist();
|
||||||
|
STATION_Utils::loadManagers();
|
||||||
|
|
||||||
iGateBeaconPacket = GPS_Utils::generateBeacon();
|
#ifdef STARTUP_DELAY // (TEST) just to wait for WiFi init of Routers
|
||||||
iGateLoRaBeaconPacket = GPS_Utils::generateiGateLoRaBeacon();
|
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";
|
||||||
|
LoRa_Utils::sendNewPacket(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
|
||||||
|
DIGI_Utils::checkEcoMode();
|
||||||
|
WIFI_Utils::setup();
|
||||||
|
NTP_Utils::setup();
|
||||||
SYSLOG_Utils::setup();
|
SYSLOG_Utils::setup();
|
||||||
BME_Utils::setup();
|
WX_Utils::setup();
|
||||||
WEB_Utils::setup();
|
WEB_Utils::setup();
|
||||||
|
TNC_Utils::setup();
|
||||||
|
#ifdef HAS_A7670
|
||||||
|
A7670_Utils::setup();
|
||||||
|
#endif
|
||||||
|
Utils::checkRebootMode();
|
||||||
|
APRS_IS_Utils::firstConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
WIFI_Utils::checkIfAutoAPShouldPowerOff();
|
WIFI_Utils::checkAutoAPTimeout();
|
||||||
|
|
||||||
if (isUpdatingOTA) {
|
if (isUpdatingOTA) {
|
||||||
ElegantOTA.loop();
|
ElegantOTA.loop();
|
||||||
return; // Don't process IGate and Digi during OTA update
|
return; // Don't process IGate and Digi during OTA update
|
||||||
}
|
}
|
||||||
|
|
||||||
thirdLine = Utils::getLocalIP();
|
if (Config.lowVoltageCutOff > 0) {
|
||||||
|
BATTERY_Utils::checkIfShouldSleep();
|
||||||
WIFI_Utils::checkWiFi(); // Always use WiFi, not related to IGate/Digi mode
|
|
||||||
// Utils::checkWiFiInterval();
|
|
||||||
|
|
||||||
if (Config.aprs_is.active && !espClient.connected()) {
|
|
||||||
APRS_IS_Utils::connect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
NTP_Utils::update();
|
||||||
|
TNC_Utils::loop();
|
||||||
|
|
||||||
Utils::checkDisplayInterval();
|
Utils::checkDisplayInterval();
|
||||||
Utils::checkBeaconInterval();
|
Utils::checkBeaconInterval();
|
||||||
|
|
||||||
String packet;
|
|
||||||
|
|
||||||
|
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) {
|
if (Config.loramodule.rxActive) {
|
||||||
packet = LoRa_Utils::receivePacket(); // We need to fetch LoRa packet above APRSIS and Digi
|
packet = LoRa_Utils::receivePacket(); // We need to fetch LoRa packet above APRSIS and Digi
|
||||||
}
|
}
|
||||||
|
|
||||||
APRS_IS_Utils::checkStatus(); // Need that to update display, maybe split this and send APRSIS status to display func?
|
if (packet != "") {
|
||||||
|
if (Config.aprs_is.active) { // If APRSIS enabled
|
||||||
|
APRS_IS_Utils::processLoRaPacket(packet); // Send received packet to APRSIS
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.aprs_is.active) { // If APRSIS enabled
|
if (Config.loramodule.txActive && (Config.digi.mode == 2 || Config.digi.mode == 3 || backUpDigiMode)) { // If Digi enabled
|
||||||
APRS_IS_Utils::loop(packet); // Send received packet to APRSIS
|
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.digi.mode == 2) { // If Digi enabled
|
if (Config.aprs_is.active) {
|
||||||
DIGI_Utils::loop(packet); // Send received packet to Digi
|
APRS_IS_Utils::listenAPRSIS(); // listen received packet from APRSIS
|
||||||
}
|
}
|
||||||
|
|
||||||
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
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);
|
||||||
}
|
}
|
||||||
@@ -4,34 +4,42 @@
|
|||||||
#include "station_utils.h"
|
#include "station_utils.h"
|
||||||
#include "syslog_utils.h"
|
#include "syslog_utils.h"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
#include "lora_utils.h"
|
#include "A7670_utils.h"
|
||||||
#include "digi_utils.h"
|
#include "digi_utils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
extern Configuration Config;
|
|
||||||
extern WiFiClient espClient;
|
extern Configuration Config;
|
||||||
extern int internalLedPin;
|
extern WiFiClient espClient;
|
||||||
extern uint32_t lastScreenOn;
|
extern uint32_t lastScreenOn;
|
||||||
extern String firstLine;
|
extern String firstLine;
|
||||||
extern String secondLine;
|
extern String secondLine;
|
||||||
extern String thirdLine;
|
extern String thirdLine;
|
||||||
extern String fourthLine;
|
extern String fourthLine;
|
||||||
extern String fifthLine;
|
extern String fifthLine;
|
||||||
extern String sixthLine;
|
extern String sixthLine;
|
||||||
extern String seventhLine;
|
extern String seventhLine;
|
||||||
|
extern bool modemLoggedToAPRSIS;
|
||||||
|
extern bool backUpDigiMode;
|
||||||
|
|
||||||
|
uint32_t lastRxTime = millis();
|
||||||
|
bool passcodeValid = false;
|
||||||
|
|
||||||
|
#ifdef HAS_A7670
|
||||||
|
extern bool stationBeacon;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace APRS_IS_Utils {
|
namespace APRS_IS_Utils {
|
||||||
|
|
||||||
void upload(String line) {
|
void upload(const String& line) {
|
||||||
espClient.print(line + "\r\n");
|
espClient.print(line + "\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect(){
|
void connect() {
|
||||||
int count = 0;
|
|
||||||
String aprsauth;
|
|
||||||
Serial.print("Connecting to APRS-IS ... ");
|
Serial.print("Connecting to APRS-IS ... ");
|
||||||
|
uint8_t count = 0;
|
||||||
while (!espClient.connect(Config.aprs_is.server.c_str(), Config.aprs_is.port) && count < 20) {
|
while (!espClient.connect(Config.aprs_is.server.c_str(), Config.aprs_is.port) && count < 20) {
|
||||||
Serial.println("Didn't connect with server...");
|
Serial.println("Didn't connect with server...");
|
||||||
delay(1000);
|
delay(1000);
|
||||||
@@ -45,193 +53,321 @@ namespace APRS_IS_Utils {
|
|||||||
if (count == 20) {
|
if (count == 20) {
|
||||||
Serial.println("Tried: " + String(count) + " FAILED!");
|
Serial.println("Tried: " + String(count) + " FAILED!");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Connected!\n(Server: " + String(Config.aprs_is.server) + " / Port: " + String(Config.aprs_is.port) +")");
|
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 filter = "t/m/" + Config.callsign + "/" + (String)Config.aprs_is.reportingDistance;
|
||||||
|
String aprsAuth = "user ";
|
||||||
aprsauth = "user " + Config.callsign + " pass " + Config.aprs_is.passcode + " vers CA2RXU_LoRa_iGate 1.3 filter " + Config.aprs_is.filter;// + "\r\n";
|
aprsAuth += Config.callsign;
|
||||||
upload(aprsauth);
|
aprsAuth += " pass ";
|
||||||
delay(200);
|
aprsAuth += Config.aprs_is.passcode;
|
||||||
|
aprsAuth += " vers CA2RXU_iGate 2.3 filter ";
|
||||||
|
aprsAuth += Config.aprs_is.filter;
|
||||||
|
upload(aprsAuth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkStatus() {
|
void checkStatus() {
|
||||||
String wifiState, aprsisState;
|
String wifiState, aprsisState;
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
wifiState = "OK";
|
wifiState = "OK";
|
||||||
} else {
|
} else {
|
||||||
wifiState = "AP";
|
if (backUpDigiMode || Config.digi.ecoMode) {
|
||||||
|
wifiState = "--";
|
||||||
if (!Config.display.alwaysOn) {
|
} else {
|
||||||
display_toggle(true);
|
wifiState = "AP";
|
||||||
|
}
|
||||||
|
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||||
|
displayToggle(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.aprs_is.active) {
|
if (!Config.aprs_is.active) {
|
||||||
aprsisState = "OFF";
|
aprsisState = "OFF";
|
||||||
} else if (espClient.connected()) {
|
|
||||||
aprsisState = "OK";
|
|
||||||
} else {
|
} else {
|
||||||
aprsisState = "--";
|
#ifdef HAS_A7670
|
||||||
|
if (modemLoggedToAPRSIS) {
|
||||||
if (!Config.display.alwaysOn) {
|
aprsisState = "OK";
|
||||||
display_toggle(true);
|
} else {
|
||||||
}
|
aprsisState = "--";
|
||||||
|
}
|
||||||
lastScreenOn = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
secondLine = "WiFi: " + wifiState + " APRS-IS: " + aprsisState;
|
|
||||||
}
|
|
||||||
|
|
||||||
String createPacket(String packet) {
|
|
||||||
if (!(Config.aprs_is.active && Config.digi.mode == 0)) { // Check if NOT only IGate
|
|
||||||
return packet.substring(3, packet.indexOf(":")) + ",qAR," + Config.callsign + packet.substring(packet.indexOf(":"));// + "\n";
|
|
||||||
} else {
|
|
||||||
return packet.substring(3, packet.indexOf(":")) + ",qAO," + Config.callsign + packet.substring(packet.indexOf(":"));// + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processLoRaPacket(String packet) {
|
|
||||||
bool queryMessage = false;
|
|
||||||
String aprsPacket, Sender, AddresseeAndMessage, Addressee, ackMessage, receivedMessage;
|
|
||||||
if (packet != "") {
|
|
||||||
#ifdef TextSerialOutputForApp
|
|
||||||
Serial.println(packet.substring(3));
|
|
||||||
#else
|
#else
|
||||||
Serial.print("Received Lora Packet : " + String(packet));
|
if (espClient.connected()) {
|
||||||
#endif
|
aprsisState = "OK";
|
||||||
if ((packet.substring(0,3) == "\x3c\xff\x01") && (packet.indexOf("TCPIP") == -1) && (packet.indexOf("NOGATE") == -1) && (packet.indexOf("RFONLY") == -1)) {
|
} else {
|
||||||
#ifndef TextSerialOutputForApp
|
aprsisState = "--";
|
||||||
Serial.print(" ---> APRS LoRa Packet!");
|
}
|
||||||
#endif
|
#endif
|
||||||
Sender = packet.substring(3,packet.indexOf(">"));
|
if(aprsisState == "--" && !Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||||
if (Sender != Config.callsign) { // avoid listening yourself by digirepeating
|
displayToggle(true);
|
||||||
AddresseeAndMessage = packet.substring(packet.indexOf("::")+2);
|
lastScreenOn = millis();
|
||||||
Addressee = AddresseeAndMessage.substring(0,AddresseeAndMessage.indexOf(":"));
|
}
|
||||||
Addressee.trim();
|
}
|
||||||
|
secondLine = "WiFi: ";
|
||||||
if (packet.indexOf("::") > 10 && Addressee == Config.callsign) { // its a message for me!
|
secondLine += wifiState;
|
||||||
if (AddresseeAndMessage.indexOf("{")>0) { // ack?
|
secondLine += " APRS-IS: ";
|
||||||
ackMessage = "ack" + AddresseeAndMessage.substring(AddresseeAndMessage.indexOf("{")+1);
|
secondLine += aprsisState;
|
||||||
ackMessage.trim();
|
}
|
||||||
delay(4000);
|
|
||||||
//Serial.println(ackMessage);
|
String checkForStartingBytes(const String& packet) {
|
||||||
for(int i = Sender.length(); i < 9; i++) {
|
if (packet.indexOf("\x3c\xff\x01") != -1) {
|
||||||
Sender += ' ';
|
return packet.substring(0, packet.indexOf("\x3c\xff\x01"));
|
||||||
}
|
} else {
|
||||||
LoRa_Utils::sendNewPacket("APRS", Config.callsign + ">APLRG1,RFONLY,WIDE1-1::" + Sender + ":" + ackMessage);
|
return packet;
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":")+1, AddresseeAndMessage.indexOf("{"));
|
}
|
||||||
} else {
|
}
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":")+1);
|
|
||||||
}
|
String buildPacketToUpload(const String& packet) {
|
||||||
if (receivedMessage.indexOf("?") == 0) {
|
String buildedPacket = packet.substring(3, packet.indexOf(":"));
|
||||||
queryMessage = true;
|
if (!(Config.aprs_is.active && Config.digi.mode == 0)) { // Check if NOT only IGate
|
||||||
delay(2000);
|
buildedPacket += ",qAR,";
|
||||||
if (!Config.display.alwaysOn) {
|
} else {
|
||||||
display_toggle(true);
|
buildedPacket += ",qAO,";
|
||||||
}
|
}
|
||||||
LoRa_Utils::sendNewPacket("APRS", QUERY_Utils::process(receivedMessage, Sender, "LoRa"));
|
buildedPacket += Config.callsign;
|
||||||
lastScreenOn = millis();
|
buildedPacket += checkForStartingBytes(packet.substring(packet.indexOf(":")));
|
||||||
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, "Callsign = " + Sender, "TYPE --> QUERY", 0);
|
return buildedPacket;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!queryMessage) {
|
bool processReceivedLoRaMessage(const String& sender, const String& packet, bool thirdParty) {
|
||||||
aprsPacket = createPacket(packet);
|
String receivedMessage;
|
||||||
if (!Config.display.alwaysOn) {
|
if (packet.indexOf("{") > 0) { // ack?
|
||||||
display_toggle(true);
|
String ackMessage = "ack";
|
||||||
}
|
ackMessage.concat(packet.substring(packet.indexOf("{") + 1));
|
||||||
lastScreenOn = millis();
|
ackMessage.trim();
|
||||||
upload(aprsPacket);
|
//Serial.println(ackMessage);
|
||||||
#ifndef TextSerialOutputForApp
|
|
||||||
Serial.println(" ---> Uploaded to APRS-IS");
|
String addToBuffer = Config.callsign;
|
||||||
#endif
|
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);
|
STATION_Utils::updateLastHeard(Sender);
|
||||||
Utils::typeOfPacket(aprsPacket, "LoRa-APRS");
|
Utils::typeOfPacket(packet.substring(3), 0); // LoRa-APRS
|
||||||
show_display(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
#ifndef TextSerialOutputForApp
|
|
||||||
Serial.println(" ---> LoRa Packet Ignored (first 3 bytes or TCPIP/NOGATE/RFONLY)\n");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processAPRSISPacket(String packet) {
|
String buildPacketToTx(const String& aprsisPacket, uint8_t packetType) {
|
||||||
String Sender, AddresseeAndMessage, Addressee, receivedMessage;
|
String packet = aprsisPacket;
|
||||||
if (!packet.startsWith("#")){
|
packet.trim();
|
||||||
if (packet.indexOf("::")>0) {
|
String outputPacket = Config.callsign;
|
||||||
Sender = packet.substring(0,packet.indexOf(">"));
|
outputPacket += ">APLRG1";
|
||||||
AddresseeAndMessage = packet.substring(packet.indexOf("::")+2);
|
if (Config.beacon.path != "") {
|
||||||
Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
outputPacket += ",";
|
||||||
|
outputPacket += Config.beacon.path;
|
||||||
|
}
|
||||||
|
outputPacket += ":}";
|
||||||
|
outputPacket += packet.substring(0, packet.indexOf(",")); // Callsign>Tocall
|
||||||
|
outputPacket.concat(",TCPIP,");
|
||||||
|
outputPacket.concat(Config.callsign);
|
||||||
|
outputPacket.concat("*");
|
||||||
|
switch (packetType) {
|
||||||
|
case 0: // gps
|
||||||
|
if (packet.indexOf(":=") > 0) {
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":="));
|
||||||
|
} else {
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":!"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // messages
|
||||||
|
outputPacket += packet.substring(packet.indexOf("::"));
|
||||||
|
break;
|
||||||
|
case 2: // status
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":>"));
|
||||||
|
break;
|
||||||
|
case 3: // telemetry
|
||||||
|
outputPacket += packet.substring(packet.indexOf("::"));
|
||||||
|
break;
|
||||||
|
case 4: // mic-e
|
||||||
|
if (packet.indexOf(":`") > 0) {
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":`"));
|
||||||
|
} else {
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":'"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 5: // object
|
||||||
|
outputPacket += packet.substring(packet.indexOf(":;"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return outputPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processAPRSISPacket(const String& packet) {
|
||||||
|
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();
|
Addressee.trim();
|
||||||
if (Addressee == Config.callsign) { // its for me!
|
if (Addressee == Config.callsign) { // its for me!
|
||||||
if (AddresseeAndMessage.indexOf("{")>0) { // ack?
|
String receivedMessage;
|
||||||
String ackMessage = "ack" + AddresseeAndMessage.substring(AddresseeAndMessage.indexOf("{")+1);
|
if (AddresseeAndMessage.indexOf("{") > 0) { // ack?
|
||||||
|
String ackMessage = "ack";
|
||||||
|
ackMessage += AddresseeAndMessage.substring(AddresseeAndMessage.indexOf("{") + 1);
|
||||||
ackMessage.trim();
|
ackMessage.trim();
|
||||||
delay(4000);
|
delay(4000);
|
||||||
//Serial.println(ackMessage);
|
for (int i = Sender.length(); i < 9; i++) {
|
||||||
for(int i = Sender.length(); i < 9; i++) {
|
|
||||||
Sender += ' ';
|
Sender += ' ';
|
||||||
}
|
}
|
||||||
String ackPacket = Config.callsign + ">APLRG1,TCPIP,qAC::" + Sender + ":" + ackMessage;// + "\n";
|
|
||||||
upload(ackPacket);
|
String ackPacket = Config.callsign;
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":")+1, AddresseeAndMessage.indexOf("{"));
|
ackPacket += ">APLRG1,TCPIP,qAC::";
|
||||||
|
ackPacket += Sender;
|
||||||
|
ackPacket += ":";
|
||||||
|
ackPacket += ackMessage;
|
||||||
|
#ifdef HAS_A7670
|
||||||
|
A7670_Utils::uploadToAPRSIS(ackPacket);
|
||||||
|
#else
|
||||||
|
upload(ackPacket);
|
||||||
|
#endif
|
||||||
|
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1, AddresseeAndMessage.indexOf("{"));
|
||||||
} else {
|
} else {
|
||||||
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":")+1);
|
receivedMessage = AddresseeAndMessage.substring(AddresseeAndMessage.indexOf(":") + 1);
|
||||||
}
|
}
|
||||||
if (receivedMessage.indexOf("?") == 0) {
|
if (receivedMessage.indexOf("?") == 0) {
|
||||||
#ifndef TextSerialOutputForApp
|
Utils::println("Rx Query (APRS-IS) : " + packet);
|
||||||
Serial.println("Received Query APRS-IS : " + packet);
|
Sender.trim();
|
||||||
#endif
|
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, true, false);
|
||||||
String queryAnswer = QUERY_Utils::process(receivedMessage, Sender, "APRSIS");
|
|
||||||
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
//Serial.println("---> QUERY Answer : " + queryAnswer.substring(0,queryAnswer.indexOf("\n")));
|
||||||
if (!Config.display.alwaysOn) {
|
if (!Config.display.alwaysOn && Config.display.timeout != 0) {
|
||||||
display_toggle(true);
|
displayToggle(true);
|
||||||
}
|
}
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
delay(500);
|
delay(500);
|
||||||
upload(queryAnswer);
|
#ifdef HAS_A7670
|
||||||
SYSLOG_Utils::log("APRSIS Tx", queryAnswer,0,0,0);
|
A7670_Utils::uploadToAPRSIS(queryAnswer);
|
||||||
|
#else
|
||||||
|
upload(queryAnswer);
|
||||||
|
#endif
|
||||||
|
SYSLOG_Utils::log(2, queryAnswer, 0, 0.0, 0); // APRSIS TX
|
||||||
fifthLine = "APRS-IS ----> APRS-IS";
|
fifthLine = "APRS-IS ----> APRS-IS";
|
||||||
sixthLine = Config.callsign;
|
sixthLine = Config.callsign;
|
||||||
for (int j=sixthLine.length();j<9;j++) {
|
for (int j = sixthLine.length();j < 9;j++) {
|
||||||
sixthLine += " ";
|
sixthLine += " ";
|
||||||
}
|
}
|
||||||
sixthLine += "> " + Sender;
|
sixthLine += "> ";
|
||||||
seventhLine = "QUERY = " + receivedMessage;
|
sixthLine += Sender;
|
||||||
|
seventhLine = "QUERY = ";
|
||||||
|
seventhLine += receivedMessage;
|
||||||
}
|
}
|
||||||
|
displayShow(firstLine, secondLine, thirdLine, fourthLine, fifthLine, sixthLine, seventhLine, 0);
|
||||||
} else {
|
} else {
|
||||||
#ifndef TextSerialOutputForApp
|
Utils::print("Rx Message (APRS-IS): " + packet);
|
||||||
Serial.print("Received from APRS-IS : " + packet);
|
if (STATION_Utils::wasHeard(Addressee) && packet.indexOf("EQNS.") == -1 && packet.indexOf("UNIT.") == -1 && packet.indexOf("PARM.") == -1) {
|
||||||
#endif
|
STATION_Utils::addToOutputPacketBuffer(buildPacketToTx(packet, 1));
|
||||||
|
displayToggle(true);
|
||||||
if (Config.aprs_is.toRF && STATION_Utils::wasHeard(Addressee)) {
|
|
||||||
LoRa_Utils::sendNewPacket("APRS", LoRa_Utils::generatePacket(packet));
|
|
||||||
display_toggle(true);
|
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
Utils::typeOfPacket(packet, "APRS-LoRa");
|
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::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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(String packet) {
|
void listenAPRSIS() {
|
||||||
if (espClient.connected()) {
|
#ifdef HAS_A7670
|
||||||
processLoRaPacket(packet);
|
A7670_Utils::listenAPRSIS();
|
||||||
|
#else
|
||||||
|
if (espClient.connected()) {
|
||||||
|
if (espClient.available()) {
|
||||||
|
String aprsisPacket = espClient.readStringUntil('\r');
|
||||||
|
aprsisPacket.trim(); // Serial.println(aprsisPacket);
|
||||||
|
processAPRSISPacket(aprsisPacket);
|
||||||
|
lastRxTime = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (espClient.available()) {
|
void firstConnection() {
|
||||||
String aprsisPacket = espClient.readStringUntil('\r');
|
if (Config.aprs_is.active && (WiFi.status() == WL_CONNECTED) && !espClient.connected()) {
|
||||||
|
connect();
|
||||||
// Serial.println(aprsisPacket);
|
while (!passcodeValid) {
|
||||||
|
listenAPRSIS();
|
||||||
processAPRSISPacket(aprsisPacket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
#ifndef APRS_IS_UTILS_H_
|
|
||||||
#define APRS_IS_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
//#define TextSerialOutputForApp
|
|
||||||
/* uncomment the previous line to get text from Serial-Output over USB into PC for:
|
|
||||||
- PinPoint App ( https://www.pinpointaprs.com )
|
|
||||||
- APRSIS32 App ( http://aprsisce.wikidot.com )
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
namespace APRS_IS_Utils {
|
|
||||||
|
|
||||||
void upload(String line);
|
|
||||||
void connect();
|
|
||||||
void checkStatus();
|
|
||||||
String createPacket(String unprocessedPacket);
|
|
||||||
void processLoRaPacket(String packet);
|
|
||||||
void processAPRSISPacket(String packet);
|
|
||||||
void loop(String packet);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,46 +1,267 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
#include "battery_utils.h"
|
#include "battery_utils.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "pins_config.h"
|
#include "board_pinout.h"
|
||||||
|
#include "power_utils.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
extern Configuration Config;
|
|
||||||
|
|
||||||
float adcReadingTransformation = (3.3/4095);
|
extern Configuration Config;
|
||||||
float voltageDividerCorrection = 0.288;
|
extern uint32_t lastBatteryCheck;
|
||||||
|
|
||||||
// for External Voltage Measurment (MAX = 15Volts !!!)
|
bool shouldSleepLowVoltage = false;
|
||||||
float R1 = 100.000; //in Kilo-Ohms
|
|
||||||
float R2 = 27.000; //in Kilo-Ohms
|
float adcReadingTransformation = (3.3/4095);
|
||||||
float readingCorrection = 0.125;
|
float voltageDividerCorrection = 0.288;
|
||||||
float multiplyCorrection = 0.035;
|
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 {
|
namespace BATTERY_Utils {
|
||||||
|
|
||||||
float checkBattery() {
|
float mapVoltage(float voltage, float in_min, float in_max, float out_min, float out_max) {
|
||||||
int sample;
|
return (voltage - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
int sampleSum = 0;
|
}
|
||||||
for (int i=0; i<100; i++) {
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
|
void adcCalibration() {
|
||||||
sample = analogRead(batteryPin);
|
#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()) {
|
||||||
|
return POWER_Utils::getBatteryVoltage();
|
||||||
|
} else {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int sample;
|
||||||
|
int sampleSum = 0;
|
||||||
|
#ifdef ADC_CTRL
|
||||||
|
#if defined(HELTEC_WIRELESS_TRACKER) || defined(HELTEC_V3_2)
|
||||||
|
digitalWrite(ADC_CTRL, HIGH);
|
||||||
|
#endif
|
||||||
|
#if defined(HELTEC_V3) || defined(HELTEC_V2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WP)
|
||||||
|
digitalWrite(ADC_CTRL, LOW);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(HELTEC_V3) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
|
|
||||||
sample = 0;
|
for (int i = 0; i < 100; i++) {
|
||||||
|
#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) || defined(HELTEC_V3_2)
|
||||||
|
digitalWrite(ADC_CTRL, LOW);
|
||||||
|
#endif
|
||||||
|
#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
|
||||||
|
#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
|
#endif
|
||||||
sampleSum += sample;
|
// return mapVoltage(voltage, 3.34, 4.71, 3.0, 4.2); // mapped voltage
|
||||||
delayMicroseconds(50);
|
#endif
|
||||||
}
|
|
||||||
return (2 * (sampleSum/100) * adcReadingTransformation) + voltageDividerCorrection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float checkExternalVoltage() {
|
float checkExternalVoltage() {
|
||||||
int sample;
|
int sample;
|
||||||
int sampleSum = 0;
|
int sampleSum = 0;
|
||||||
for (int i=0; i<100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
sample = analogRead(Config.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;
|
sampleSum += sample;
|
||||||
delayMicroseconds(50);
|
delayMicroseconds(50);
|
||||||
}
|
}
|
||||||
return ((((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 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
|
||||||
|
#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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef BATTERY_UTILS_H_
|
|
||||||
#define BATTERY_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace BATTERY_Utils {
|
|
||||||
|
|
||||||
float checkBattery();
|
|
||||||
float checkExternalVoltage();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
#include "bme_utils.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "gps_utils.h"
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
#define SEALEVELPRESSURE_HPA (1013.25)
|
|
||||||
#define HEIGHT_CORRECTION 0 // in meters
|
|
||||||
#define CORRECTION_FACTOR (8.2296) // for meters
|
|
||||||
|
|
||||||
extern Configuration Config;
|
|
||||||
extern String fifthLine;
|
|
||||||
extern uint32_t bmeLastReading;
|
|
||||||
|
|
||||||
float newHum, newTemp, newPress, newGas;
|
|
||||||
|
|
||||||
|
|
||||||
namespace BME_Utils {
|
|
||||||
|
|
||||||
#ifdef BME280Sensor
|
|
||||||
Adafruit_BME280 bme;
|
|
||||||
#endif
|
|
||||||
#ifdef BMP280Sensor
|
|
||||||
Adafruit_BMP280 bme;
|
|
||||||
#endif
|
|
||||||
#ifdef BME680Sensor
|
|
||||||
Adafruit_BME680 bme;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
if (Config.bme.active) {
|
|
||||||
bool status;
|
|
||||||
status = bme.begin(0x76); // Don't forget to join pins for righ direction on BME280!
|
|
||||||
if (!status) {
|
|
||||||
Serial.println("Could not find a valid BME280 or BMP280 sensor, check wiring!");
|
|
||||||
show_display("ERROR", "", "BME/BMP sensor active", "but no sensor found...");
|
|
||||||
while (1); // sacar esto para que quede pegado si no encuentra BME280
|
|
||||||
} else {
|
|
||||||
#ifdef BME280Sensor
|
|
||||||
bme.setSampling(Adafruit_BME280::MODE_FORCED,
|
|
||||||
Adafruit_BME280::SAMPLING_X1,
|
|
||||||
Adafruit_BME280::SAMPLING_X1,
|
|
||||||
Adafruit_BME280::SAMPLING_X1,
|
|
||||||
Adafruit_BME280::FILTER_OFF
|
|
||||||
);
|
|
||||||
Serial.println("init : BME280 Module ... done!");
|
|
||||||
#endif
|
|
||||||
#ifdef BMP280Sensor
|
|
||||||
bme.setSampling(Adafruit_BMP280::MODE_FORCED,
|
|
||||||
Adafruit_BMP280::SAMPLING_X1,
|
|
||||||
Adafruit_BMP280::SAMPLING_X1,
|
|
||||||
Adafruit_BMP280::FILTER_OFF
|
|
||||||
);
|
|
||||||
Serial.println("init : BMP280 Module ... done!");
|
|
||||||
#endif
|
|
||||||
#ifdef BME680Sensor
|
|
||||||
bme.setTemperatureOversampling(BME680_OS_1X);
|
|
||||||
bme.setHumidityOversampling(BME680_OS_1X);
|
|
||||||
bme.setPressureOversampling(BME680_OS_1X);
|
|
||||||
bme.setIIRFilterSize(BME680_FILTER_SIZE_0);
|
|
||||||
Serial.println("init : BME680 Module ... done!");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Serial.println("(BME/BMP sensor not 'active' in 'igate_conf.json')");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String generateTempString(float bmeTemp) {
|
|
||||||
String strTemp;
|
|
||||||
strTemp = String((int)bmeTemp);
|
|
||||||
switch (strTemp.length()) {
|
|
||||||
case 1:
|
|
||||||
return "00" + strTemp;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
return "0" + strTemp;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
return strTemp;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "-999";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String generateHumString(float bmeHum) {
|
|
||||||
String strHum;
|
|
||||||
strHum = String((int)bmeHum);
|
|
||||||
switch (strHum.length()) {
|
|
||||||
case 1:
|
|
||||||
return "0" + strHum;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
return strHum;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ((int)bmeHum == 100) {
|
|
||||||
return "00";
|
|
||||||
} else {
|
|
||||||
return "-99";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "-99";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String generatePresString(float bmePress) {
|
|
||||||
String strPress;
|
|
||||||
strPress = String((int)bmePress);
|
|
||||||
switch (strPress.length()) {
|
|
||||||
case 1:
|
|
||||||
return "000" + strPress + "0";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
return "00" + strPress + "0";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
return "0" + strPress + "0";
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
return strPress + "0";
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
return strPress;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "-99999";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String readDataSensor() {
|
|
||||||
String wx, tempStr, humStr, presStr;
|
|
||||||
|
|
||||||
uint32_t lastReading = millis() - bmeLastReading;
|
|
||||||
if (lastReading > 60*1000) {
|
|
||||||
#if defined(BME280Sensor) || defined(BMP280Sensor)
|
|
||||||
bme.takeForcedMeasurement();
|
|
||||||
newTemp = bme.readTemperature();
|
|
||||||
newPress = (bme.readPressure() / 100.0F);
|
|
||||||
#ifdef BME280Sensor
|
|
||||||
newHum = bme.readHumidity();
|
|
||||||
#endif
|
|
||||||
#ifdef BMP280Sensor
|
|
||||||
newHum = 0;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BME680Sensor
|
|
||||||
bme.performReading();
|
|
||||||
delay(50);
|
|
||||||
if (bme.endReading()) {
|
|
||||||
newTemp = bme.temperature;
|
|
||||||
newPress = (bme.pressure / 100.0F);
|
|
||||||
newHum = bme.humidity;
|
|
||||||
newGas = bme.gas_resistance / 1000.0; // in Kilo ohms
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
bmeLastReading = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) {
|
|
||||||
Serial.println("BME/BMP Module data failed");
|
|
||||||
wx = ".../...g...t...r...p...P...h..b.....";
|
|
||||||
fifthLine = "";
|
|
||||||
return wx;
|
|
||||||
} else {
|
|
||||||
tempStr = generateTempString((newTemp * 1.8) + 32);
|
|
||||||
#if defined(BME280Sensor) || defined(BME680Sensor)
|
|
||||||
humStr = generateHumString(newHum);
|
|
||||||
#endif
|
|
||||||
#ifdef BMP280Sensor
|
|
||||||
humStr = "..";
|
|
||||||
#endif
|
|
||||||
presStr = generatePresString(newPress + (HEIGHT_CORRECTION/CORRECTION_FACTOR));
|
|
||||||
fifthLine = "BME-> " + String(int(newTemp))+"C " + humStr + "% " + presStr.substring(0,4) + "hPa";
|
|
||||||
wx = ".../...g...t" + tempStr + "r...p...P...h" + humStr + "b" + presStr;
|
|
||||||
#ifdef BME680Sensor
|
|
||||||
wx += "Gas: " + String(newGas) + "Kohms ";
|
|
||||||
#endif
|
|
||||||
return wx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#ifndef BME_UTILS_H_
|
|
||||||
#define BME_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
|
||||||
|
|
||||||
#define BME280Sensor // its set by default but you should comment it with "//"
|
|
||||||
//#define BMP280Sensor // and delete "//" from the one you want to use.
|
|
||||||
//#define BME680Sensor
|
|
||||||
|
|
||||||
#ifdef BME280Sensor
|
|
||||||
#include <Adafruit_BME280.h>
|
|
||||||
#endif
|
|
||||||
#ifdef BMP280Sensor
|
|
||||||
#include <Adafruit_BMP280.h>
|
|
||||||
#endif
|
|
||||||
#ifdef BME680Sensor
|
|
||||||
#include <Adafruit_BME680.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace BME_Utils {
|
|
||||||
|
|
||||||
void setup();
|
|
||||||
|
|
||||||
String generateTempString(float bmeTemp);
|
|
||||||
String generateHumString(float bmeHum);
|
|
||||||
String generatePresString(float bmePress);
|
|
||||||
String readDataSensor();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,94 +3,112 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
void Configuration::check() {
|
|
||||||
if (reload) {
|
|
||||||
show_display("------- UPDATE ------", "config is old", "device will update", "and then reboot", 1000);
|
|
||||||
|
|
||||||
writeFile();
|
|
||||||
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Configuration::writeFile() {
|
void Configuration::writeFile() {
|
||||||
Serial.println("Saving config..");
|
Serial.println("Saving config..");
|
||||||
|
|
||||||
StaticJsonDocument<1536> data;
|
StaticJsonDocument<2560> data;
|
||||||
File configFile = SPIFFS.open("/igate_conf.json", "w");
|
File configFile = SPIFFS.open("/igate_conf.json", "w");
|
||||||
|
|
||||||
if (wifiAPs[0].ssid != "") { // We don't want to save Auto AP empty SSID
|
if (wifiAPs[0].ssid != "") { // We don't want to save Auto AP empty SSID
|
||||||
for (int i = 0; i < wifiAPs.size(); i++) {
|
for (int i = 0; i < wifiAPs.size(); i++) {
|
||||||
data["wifi"]["AP"][i]["ssid"] = wifiAPs[i].ssid;
|
data["wifi"]["AP"][i]["ssid"] = wifiAPs[i].ssid;
|
||||||
data["wifi"]["AP"][i]["password"] = wifiAPs[i].password;
|
data["wifi"]["AP"][i]["password"] = wifiAPs[i].password;
|
||||||
// data["wifi"]["AP"][i]["latitude"] = wifiAPs[i].latitude;
|
|
||||||
// data["wifi"]["AP"][i]["longitude"] = wifiAPs[i].longitude;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
|
data["wifi"]["autoAP"]["password"] = wifiAutoAP.password;
|
||||||
data["wifi"]["autoAP"]["powerOff"] = wifiAutoAP.powerOff;
|
data["wifi"]["autoAP"]["timeout"] = wifiAutoAP.timeout;
|
||||||
|
|
||||||
data["callsign"] = callsign;
|
data["callsign"] = callsign;
|
||||||
// data["stationMode"] = stationMode; // only check for config version
|
|
||||||
// data["iGateComment"] = iGateComment;
|
|
||||||
|
|
||||||
// data["other"]["beaconInterval"] = beaconInterval;
|
data["aprs_is"]["active"] = aprs_is.active;
|
||||||
// data["other"]["igateSendsLoRaBeacons"] = igateSendsLoRaBeacons;
|
data["aprs_is"]["passcode"] = aprs_is.passcode;
|
||||||
// data["other"]["igateRepeatsLoRaPackets"] = igateRepeatsLoRaPackets;
|
data["aprs_is"]["server"] = aprs_is.server;
|
||||||
data["other"]["rememberStationTime"] = rememberStationTime;
|
data["aprs_is"]["port"] = aprs_is.port;
|
||||||
data["other"]["sendBatteryVoltage"] = sendBatteryVoltage;
|
data["aprs_is"]["filter"] = aprs_is.filter;
|
||||||
data["other"]["externalVoltageMeasurement"] = externalVoltageMeasurement;
|
data["aprs_is"]["messagesToRF"] = aprs_is.messagesToRF;
|
||||||
data["other"]["externalVoltagePin"] = externalVoltagePin;
|
data["aprs_is"]["objectsToRF"] = aprs_is.objectsToRF;
|
||||||
|
|
||||||
data["digi"]["mode"] = digi.mode;
|
data["beacon"]["comment"] = beacon.comment;
|
||||||
// data["digi"]["comment"] = digi.comment;
|
data["beacon"]["interval"] = beacon.interval;
|
||||||
// data["digi"]["latitude"] = digi.latitude;
|
data["beacon"]["latitude"] = beacon.latitude;
|
||||||
// data["digi"]["longitude"] = digi.longitude;
|
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["aprs_is"]["active"] = aprs_is.active;
|
data["beacon"]["gpsActive"] = beacon.gpsActive;
|
||||||
data["aprs_is"]["passcode"] = aprs_is.passcode;
|
data["beacon"]["gpsAmbiguity"] = beacon.gpsAmbiguity;
|
||||||
data["aprs_is"]["server"] = aprs_is.server;
|
|
||||||
data["aprs_is"]["port"] = aprs_is.port;
|
|
||||||
data["aprs_is"]["filter"] = aprs_is.filter;
|
|
||||||
data["aprs_is"]["toRF"] = aprs_is.toRF;
|
|
||||||
|
|
||||||
data["beacon"]["comment"] = beacon.comment;
|
data["digi"]["mode"] = digi.mode;
|
||||||
// data["beacon"]["igateRepeatsLoRaPackets"] = beacon.igateRepeatsLoRaPackets;
|
data["digi"]["ecoMode"] = digi.ecoMode;
|
||||||
// data["beacon"]["igateSendsLoRaBeacons"] = beacon.igateSendsLoRaBeacons;
|
|
||||||
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["lora"]["iGateFreq"] = loramodule.iGateFreq;
|
data["lora"]["rxFreq"] = loramodule.rxFreq;
|
||||||
// data["lora"]["digirepeaterTxFreq"] = loramodule.digirepeaterTxFreq;
|
data["lora"]["txFreq"] = loramodule.txFreq;
|
||||||
// data["lora"]["digirepeaterRxFreq"] = loramodule.digirepeaterRxFreq;
|
data["lora"]["spreadingFactor"] = loramodule.spreadingFactor;
|
||||||
data["lora"]["rxFreq"] = loramodule.rxFreq;
|
data["lora"]["signalBandwidth"] = loramodule.signalBandwidth;
|
||||||
data["lora"]["txFreq"] = loramodule.txFreq;
|
data["lora"]["codingRate4"] = loramodule.codingRate4;
|
||||||
data["lora"]["spreadingFactor"] = loramodule.spreadingFactor;
|
data["lora"]["power"] = loramodule.power;
|
||||||
data["lora"]["signalBandwidth"] = loramodule.signalBandwidth;
|
data["lora"]["txActive"] = loramodule.txActive;
|
||||||
data["lora"]["codingRate4"] = loramodule.codingRate4;
|
data["lora"]["rxActive"] = loramodule.rxActive;
|
||||||
data["lora"]["power"] = loramodule.power;
|
|
||||||
data["lora"]["txActive"] = loramodule.txActive;
|
|
||||||
data["lora"]["rxActive"] = loramodule.rxActive;
|
|
||||||
|
|
||||||
data["display"]["alwaysOn"] = display.alwaysOn;
|
data["display"]["alwaysOn"] = display.alwaysOn;
|
||||||
data["display"]["timeout"] = display.timeout;
|
data["display"]["timeout"] = display.timeout;
|
||||||
data["display"]["turn180"] = display.turn180;
|
data["display"]["turn180"] = display.turn180;
|
||||||
|
|
||||||
data["syslog"]["active"] = syslog.active;
|
data["battery"]["sendInternalVoltage"] = battery.sendInternalVoltage;
|
||||||
data["syslog"]["server"] = syslog.server;
|
data["battery"]["monitorInternalVoltage"] = battery.monitorInternalVoltage;
|
||||||
data["syslog"]["port"] = syslog.port;
|
data["battery"]["internalSleepVoltage"] = battery.internalSleepVoltage;
|
||||||
|
|
||||||
data["bme"]["active"] = bme.active;
|
data["battery"]["sendExternalVoltage"] = battery.sendExternalVoltage;
|
||||||
|
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["ota"]["username"] = ota.username;
|
data["battery"]["sendVoltageAsTelemetry"] = battery.sendVoltageAsTelemetry;
|
||||||
data["ota"]["password"] = ota.password;
|
|
||||||
|
data["wxsensor"]["active"] = wxsensor.active;
|
||||||
|
data["wxsensor"]["heightCorrection"] = wxsensor.heightCorrection;
|
||||||
|
data["wxsensor"]["temperatureCorrection"] = wxsensor.temperatureCorrection;
|
||||||
|
|
||||||
|
data["syslog"]["active"] = syslog.active;
|
||||||
|
data["syslog"]["server"] = syslog.server;
|
||||||
|
data["syslog"]["port"] = syslog.port;
|
||||||
|
|
||||||
|
data["tnc"]["enableServer"] = tnc.enableServer;
|
||||||
|
data["tnc"]["enableSerial"] = tnc.enableSerial;
|
||||||
|
data["tnc"]["acceptOwn"] = tnc.acceptOwn;
|
||||||
|
|
||||||
|
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"]["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);
|
serializeJson(data, configFile);
|
||||||
|
|
||||||
@@ -105,7 +123,7 @@ bool Configuration::readFile() {
|
|||||||
File configFile = SPIFFS.open("/igate_conf.json", "r");
|
File configFile = SPIFFS.open("/igate_conf.json", "r");
|
||||||
|
|
||||||
if (configFile) {
|
if (configFile) {
|
||||||
StaticJsonDocument<1536> data;
|
StaticJsonDocument<2560> data;
|
||||||
|
|
||||||
DeserializationError error = deserializeJson(data, configFile);
|
DeserializationError error = deserializeJson(data, configFile);
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -121,113 +139,97 @@ bool Configuration::readFile() {
|
|||||||
wifiAPs.push_back(wifiap);
|
wifiAPs.push_back(wifiap);
|
||||||
}
|
}
|
||||||
|
|
||||||
wifiAutoAP.password = data["wifi"]["autoAP"]["password"].as<String>();
|
wifiAutoAP.password = data["wifi"]["autoAP"]["password"] | "1234567890";
|
||||||
wifiAutoAP.powerOff = data["wifi"]["autoAP"]["powerOff"].as<int>();
|
wifiAutoAP.timeout = data["wifi"]["autoAP"]["timeout"] | 10;
|
||||||
|
|
||||||
callsign = data["callsign"].as<String>();
|
callsign = data["callsign"] | "NOCALL-10";
|
||||||
rememberStationTime = data["other"]["rememberStationTime"].as<int>();
|
rememberStationTime = data["other"]["rememberStationTime"] | 30;
|
||||||
sendBatteryVoltage = data["other"]["sendBatteryVoltage"].as<bool>();
|
|
||||||
externalVoltageMeasurement = data["other"]["externalVoltageMeasurement"].as<bool>();
|
|
||||||
externalVoltagePin = data["other"]["externalVoltagePin"].as<int>();
|
|
||||||
|
|
||||||
aprs_is.passcode = data["aprs_is"]["passcode"].as<String>();
|
beacon.latitude = data["beacon"]["latitude"] | 0.0;
|
||||||
aprs_is.server = data["aprs_is"]["server"].as<String>();
|
beacon.longitude = data["beacon"]["longitude"] | 0.0;
|
||||||
aprs_is.port = data["aprs_is"]["port"].as<int>();
|
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;
|
||||||
|
|
||||||
loramodule.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
beacon.gpsActive = data["beacon"]["gpsActive"] | false;
|
||||||
loramodule.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
|
beacon.gpsAmbiguity = data["beacon"]["gpsAmbiguity"] | false;
|
||||||
loramodule.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
|
||||||
loramodule.power = data["lora"]["power"].as<int>();
|
|
||||||
|
|
||||||
display.alwaysOn = data["display"]["alwaysOn"].as<bool>();
|
aprs_is.active = data["aprs_is"]["active"] | false;
|
||||||
display.timeout = data["display"]["timeout"].as<int>();
|
aprs_is.passcode = data["aprs_is"]["passcode"] | "XYZWV";
|
||||||
display.turn180 = data["display"]["turn180"].as<bool>();
|
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;
|
||||||
|
|
||||||
syslog.active = data["syslog"]["active"].as<bool>();
|
digi.mode = data["digi"]["mode"] | 0;
|
||||||
syslog.server = data["syslog"]["server"].as<String>();
|
digi.ecoMode = data["digi"]["ecoMode"] | false;
|
||||||
syslog.port = data["syslog"]["port"].as<int>();
|
|
||||||
|
|
||||||
bme.active = data["bme"]["active"].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;
|
||||||
|
|
||||||
ota.username = data["ota"]["username"].as<String>();
|
display.alwaysOn = data["display"]["alwaysOn"] | true;
|
||||||
ota.password = data["ota"]["password"].as<String>();
|
display.timeout = data["display"]["timeout"] | 4;
|
||||||
|
display.turn180 = data["display"]["turn180"] | false;
|
||||||
|
|
||||||
int stationMode = data["stationMode"].as<int>(); // deprecated but need to specify config version
|
battery.sendInternalVoltage = data["battery"]["sendInternalVoltage"] | false;
|
||||||
|
battery.monitorInternalVoltage = data["battery"]["monitorInternalVoltage"] | false;
|
||||||
|
battery.internalSleepVoltage = data["battery"]["internalSleepVoltage"] | 2.9;
|
||||||
|
|
||||||
if (stationMode == 0) {
|
battery.sendExternalVoltage = data["battery"]["sendExternalVoltage"] | false;
|
||||||
// Load new settings
|
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;
|
||||||
|
|
||||||
beacon.latitude = data["beacon"]["latitude"].as<double>();
|
battery.sendVoltageAsTelemetry = data["battery"]["sendVoltageAsTelemetry"] | false;
|
||||||
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.igateSendsLoRaBeacons = data["beacon"]["igateSendsLoRaBeacons"].as<bool>();
|
|
||||||
// beacon.igateRepeatsLoRaPackets = data["beacon"]["igateRepeatsLoRaPackets"].as<bool>();
|
|
||||||
beacon.sendViaAPRSIS = data["beacon"]["sendViaAPRSIS"].as<bool>();
|
|
||||||
beacon.sendViaRF = data["beacon"]["sendViaRF"].as<bool>();
|
|
||||||
beacon.path = data["beacon"]["path"].as<String>();
|
|
||||||
|
|
||||||
digi.mode = data["digi"]["mode"].as<int>();
|
wxsensor.active = data["wxsensor"]["active"] | false;
|
||||||
|
wxsensor.heightCorrection = data["wxsensor"]["heightCorrection"] | 0;
|
||||||
|
wxsensor.temperatureCorrection = data["wxsensor"]["temperatureCorrection"] | 0.0;
|
||||||
|
|
||||||
aprs_is.active = data["aprs_is"]["active"].as<bool>();
|
syslog.active = data["syslog"]["active"] | false;
|
||||||
aprs_is.filter = data["aprs_is"]["filter"].as<String>();
|
syslog.server = data["syslog"]["server"] | "lora.link9.net";
|
||||||
aprs_is.toRF = data["aprs_is"]["toRF"].as<bool>();
|
syslog.port = data["syslog"]["port"] | 1514;
|
||||||
|
|
||||||
loramodule.txFreq = data["lora"]["txFreq"].as<long>();
|
tnc.enableServer = data["tnc"]["enableServer"] | false;
|
||||||
loramodule.rxFreq = data["lora"]["rxFreq"].as<long>();
|
tnc.enableSerial = data["tnc"]["enableSerial"] | false;
|
||||||
loramodule.txActive = data["lora"]["txActive"].as<bool>();
|
tnc.acceptOwn = data["tnc"]["acceptOwn"] | false;
|
||||||
loramodule.rxActive = data["lora"]["rxActive"].as<bool>();
|
|
||||||
} else {
|
|
||||||
// Load old settings and put into new variables not actual config
|
|
||||||
|
|
||||||
String iGateComment = data["iGateComment"].as<String>();
|
ota.username = data["ota"]["username"] | "";
|
||||||
int beaconInterval = data["other"]["beaconInterval"].as<int>();
|
ota.password = data["ota"]["password"] | "";
|
||||||
// bool igateSendsLoRaBeacons = data["other"]["igateSendsLoRaBeacons"].as<bool>();
|
|
||||||
// bool igateRepeatsLoRaPackets = data["other"]["igateRepeatsLoRaPackets"].as<bool>();
|
|
||||||
|
|
||||||
long iGateFreq = data["lora"]["iGateFreq"].as<long>();
|
webadmin.active = data["webadmin"]["active"] | false;
|
||||||
long digirepeaterTxFreq = data["lora"]["digirepeaterTxFreq"].as<long>();
|
webadmin.username = data["webadmin"]["username"] | "admin";
|
||||||
long digirepeaterRxFreq = data["lora"]["digirepeaterRxFreq"].as<long>();
|
webadmin.password = data["webadmin"]["password"] | "";
|
||||||
|
|
||||||
String digiComment = data["digi"]["comment"].as<String>();
|
|
||||||
double digiLatitude = data["digi"]["latitude"].as<double>();
|
|
||||||
double digiLongitude = data["digi"]["longitude"].as<double>();
|
|
||||||
|
|
||||||
beacon.latitude = digiLatitude;
|
ntp.gmtCorrection = data["ntp"]["gmtCorrection"] | 0.0;
|
||||||
beacon.longitude = digiLongitude;
|
|
||||||
beacon.interval = beaconInterval;
|
|
||||||
// beacon.igateSendsLoRaBeacons = igateSendsLoRaBeacons;
|
|
||||||
// beacon.igateRepeatsLoRaPackets = igateRepeatsLoRaPackets;
|
|
||||||
loramodule.txFreq = digirepeaterTxFreq;
|
|
||||||
loramodule.rxFreq = digirepeaterRxFreq;
|
|
||||||
loramodule.rxActive = true;
|
|
||||||
beacon.sendViaAPRSIS = true;
|
|
||||||
beacon.sendViaRF = false;
|
|
||||||
|
|
||||||
switch (stationMode) {
|
lowPowerMode = data["other"]["lowPowerMode"] | false;
|
||||||
case 1: // IGate only
|
lowVoltageCutOff = data["other"]["lowVoltageCutOff"] | 0;
|
||||||
// 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;
|
backupDigiMode = data["other"]["backupDigiMode"] | false;
|
||||||
}
|
|
||||||
|
rebootMode = data["other"]["rebootMode"] | false;
|
||||||
|
rebootModeTime = data["other"]["rebootModeTime"] | 6;
|
||||||
|
|
||||||
|
personalNote = data["personalNote"] | "personal note here";
|
||||||
|
|
||||||
|
blacklist = data["blacklist"] | "station callsign";
|
||||||
|
|
||||||
|
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
|
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;
|
WiFi_AP wifiap;
|
||||||
@@ -246,80 +248,107 @@ bool Configuration::readFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Configuration::init() {
|
void Configuration::init() {
|
||||||
reload = false;
|
|
||||||
|
|
||||||
WiFi_AP wifiap;
|
WiFi_AP wifiap;
|
||||||
wifiap.ssid = "";
|
wifiap.ssid = "";
|
||||||
wifiap.password = "";
|
wifiap.password = "";
|
||||||
// wifiap.latitude = 0.0; // deprecated
|
|
||||||
// wifiap.longitude = 0.0; // deprecated
|
|
||||||
wifiAPs.push_back(wifiap);
|
wifiAPs.push_back(wifiap);
|
||||||
|
|
||||||
wifiAutoAP.password = "1234567890";
|
wifiAutoAP.password = "1234567890";
|
||||||
wifiAutoAP.powerOff = 15;
|
wifiAutoAP.timeout = 10;
|
||||||
|
|
||||||
callsign = "N0CALL";
|
callsign = "N0CALL-10";
|
||||||
// stationMode = 1; // deprecated
|
|
||||||
// iGateComment = "LoRa_APRS_iGate Development"; // deprecated
|
|
||||||
|
|
||||||
beacon.comment = "LoRa APRS"; // new
|
beacon.comment = "LoRa APRS";
|
||||||
beacon.latitude = 0.0; // new
|
beacon.latitude = 0.0;
|
||||||
beacon.longitude = 0.0; // new
|
beacon.longitude = 0.0;
|
||||||
beacon.interval = 15; // new
|
beacon.interval = 15;
|
||||||
// beacon.igateRepeatsLoRaPackets = false; // new
|
beacon.overlay = "L";
|
||||||
// beacon.igateSendsLoRaBeacons = false; // new
|
beacon.symbol = "a";
|
||||||
beacon.overlay = "L"; // new
|
beacon.sendViaAPRSIS = true;
|
||||||
beacon.symbol = "#"; // new
|
beacon.sendViaRF = false;
|
||||||
beacon.sendViaAPRSIS = true; // new
|
beacon.path = "WIDE1-1";
|
||||||
beacon.sendViaRF = false; // new
|
|
||||||
beacon.path = "WIDE1-1"; // new
|
|
||||||
|
|
||||||
digi.mode = 0; // new
|
|
||||||
// digi.comment = "LoRa_APRS_iGate Development"; // deprecated
|
|
||||||
// digi.latitude = 0.0; // deprecated
|
|
||||||
// digi.longitude = 0.0; // deprecated
|
|
||||||
|
|
||||||
aprs_is.active = false; // new
|
beacon.gpsActive = false;
|
||||||
aprs_is.passcode = "XYZVW";
|
beacon.gpsAmbiguity = false;
|
||||||
aprs_is.server = "rotate.aprs2.net";
|
|
||||||
aprs_is.port = 14580;
|
|
||||||
aprs_is.filter = "m/10"; // new
|
|
||||||
aprs_is.toRF = false; // new
|
|
||||||
|
|
||||||
// loramodule.iGateFreq = 433775000; // deprecated
|
digi.mode = 0;
|
||||||
// loramodule.digirepeaterTxFreq = 433775000; // deprecated
|
digi.ecoMode = false;
|
||||||
// loramodule.digirepeaterRxFreq = 433900000; // deprecated
|
|
||||||
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
|
|
||||||
|
|
||||||
display.alwaysOn = true;
|
tnc.enableServer = false;
|
||||||
display.timeout = 4;
|
tnc.enableSerial = false;
|
||||||
display.turn180 = false;
|
tnc.acceptOwn = false;
|
||||||
|
|
||||||
syslog.active = false;
|
aprs_is.active = false;
|
||||||
syslog.server = "192.168.0.100";
|
aprs_is.passcode = "XYZVW";
|
||||||
syslog.port = 514;
|
aprs_is.server = "rotate.aprs2.net";
|
||||||
|
aprs_is.port = 14580;
|
||||||
|
aprs_is.filter = "m/10";
|
||||||
|
aprs_is.messagesToRF = false;
|
||||||
|
aprs_is.objectsToRF = false;
|
||||||
|
|
||||||
bme.active = false;
|
loramodule.txFreq = 433775000;
|
||||||
|
loramodule.rxFreq = 433775000;
|
||||||
|
loramodule.spreadingFactor = 12;
|
||||||
|
loramodule.signalBandwidth = 125000;
|
||||||
|
loramodule.codingRate4 = 5;
|
||||||
|
loramodule.power = 20;
|
||||||
|
loramodule.txActive = false;
|
||||||
|
loramodule.rxActive = true;
|
||||||
|
|
||||||
ota.username = "";
|
display.alwaysOn = true;
|
||||||
ota.password = "";
|
display.timeout = 4;
|
||||||
|
display.turn180 = false;
|
||||||
|
|
||||||
// beaconInterval = 15; // deprecated
|
syslog.active = false;
|
||||||
// igateSendsLoRaBeacons = false; // deprecated
|
syslog.server = "lora.link9.net";
|
||||||
// igateRepeatsLoRaPackets = false; // deprecated
|
syslog.port = 1514;
|
||||||
rememberStationTime = 30;
|
|
||||||
sendBatteryVoltage = false;
|
|
||||||
externalVoltageMeasurement = false;
|
|
||||||
externalVoltagePin = 34;
|
|
||||||
|
|
||||||
Serial.println("todo escrito");
|
wxsensor.active = false;
|
||||||
|
wxsensor.heightCorrection = 0;
|
||||||
|
wxsensor.temperatureCorrection = 0.0;
|
||||||
|
|
||||||
|
ota.username = "";
|
||||||
|
ota.password = "";
|
||||||
|
|
||||||
|
rememberStationTime = 30;
|
||||||
|
|
||||||
|
battery.sendInternalVoltage = false;
|
||||||
|
battery.monitorInternalVoltage = false;
|
||||||
|
battery.internalSleepVoltage = 2.9;
|
||||||
|
|
||||||
|
battery.sendExternalVoltage = false;
|
||||||
|
battery.externalVoltagePin = 34;
|
||||||
|
battery.monitorExternalVoltage = false;
|
||||||
|
battery.externalSleepVoltage = 10.9;
|
||||||
|
battery.voltageDividerR1 = 100.0;
|
||||||
|
battery.voltageDividerR2 = 27.0;
|
||||||
|
|
||||||
|
battery.sendVoltageAsTelemetry = false;
|
||||||
|
|
||||||
|
lowPowerMode = false;
|
||||||
|
lowVoltageCutOff = 0;
|
||||||
|
|
||||||
|
backupDigiMode = false;
|
||||||
|
|
||||||
|
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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Configuration::Configuration() {
|
Configuration::Configuration() {
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
#ifndef CONFIGURATION_H_
|
|
||||||
#define CONFIGURATION_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <FS.h>
|
|
||||||
|
|
||||||
class WiFi_AP {
|
|
||||||
public:
|
|
||||||
String ssid;
|
|
||||||
String password;
|
|
||||||
// double latitude; // deprecated
|
|
||||||
// double longitude; // deprecated
|
|
||||||
};
|
|
||||||
|
|
||||||
class WiFi_Auto_AP {
|
|
||||||
public:
|
|
||||||
String password;
|
|
||||||
int powerOff;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Beacon {
|
|
||||||
public:
|
|
||||||
double latitude; // new
|
|
||||||
double longitude; // new
|
|
||||||
String comment; // new
|
|
||||||
String overlay; // new
|
|
||||||
String symbol; // new
|
|
||||||
int interval; // new
|
|
||||||
bool sendViaRF; // new
|
|
||||||
bool sendViaAPRSIS; // new
|
|
||||||
String path; // new
|
|
||||||
};
|
|
||||||
|
|
||||||
class DIGI {
|
|
||||||
public:
|
|
||||||
int mode; // new
|
|
||||||
// String comment; // deprecated
|
|
||||||
// double latitude; // deprecated
|
|
||||||
// double longitude; // deprecated
|
|
||||||
};
|
|
||||||
|
|
||||||
class APRS_IS {
|
|
||||||
public:
|
|
||||||
bool active; // new
|
|
||||||
String passcode;
|
|
||||||
String server;
|
|
||||||
int port;
|
|
||||||
// int reportingDistance; // deprecated
|
|
||||||
String filter; // new
|
|
||||||
bool toRF; // new
|
|
||||||
};
|
|
||||||
|
|
||||||
class LoraModule {
|
|
||||||
public:
|
|
||||||
// long iGateFreq; // deprecated
|
|
||||||
// long digirepeaterTxFreq; // deprecated
|
|
||||||
// long digirepeaterRxFreq; // deprecated
|
|
||||||
long txFreq; // new
|
|
||||||
long rxFreq; // new
|
|
||||||
bool txActive; // new
|
|
||||||
bool rxActive; // new
|
|
||||||
int spreadingFactor;
|
|
||||||
long signalBandwidth;
|
|
||||||
int codingRate4;
|
|
||||||
int power;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Display {
|
|
||||||
public:
|
|
||||||
bool alwaysOn;
|
|
||||||
int timeout;
|
|
||||||
bool turn180;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SYSLOG {
|
|
||||||
public:
|
|
||||||
bool active;
|
|
||||||
String server;
|
|
||||||
int port;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BME {
|
|
||||||
public:
|
|
||||||
bool active;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OTA {
|
|
||||||
public:
|
|
||||||
String username;
|
|
||||||
String password;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Configuration {
|
|
||||||
public:
|
|
||||||
bool reload;
|
|
||||||
String callsign;
|
|
||||||
// int stationMode; // deprecated
|
|
||||||
// String iGateComment; // deprecated
|
|
||||||
// int beaconInterval; // deprecated
|
|
||||||
// bool igateSendsLoRaBeacons; // deprecated
|
|
||||||
// bool igateRepeatsLoRaPackets; // deprecated
|
|
||||||
int rememberStationTime;
|
|
||||||
bool sendBatteryVoltage;
|
|
||||||
bool externalVoltageMeasurement;
|
|
||||||
int externalVoltagePin;
|
|
||||||
std::vector<WiFi_AP> wifiAPs;
|
|
||||||
WiFi_Auto_AP wifiAutoAP;
|
|
||||||
Beacon beacon; // new
|
|
||||||
DIGI digi;
|
|
||||||
APRS_IS aprs_is;
|
|
||||||
LoraModule loramodule;
|
|
||||||
Display display;
|
|
||||||
SYSLOG syslog;
|
|
||||||
BME bme;
|
|
||||||
OTA ota;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void writeFile();
|
|
||||||
void check();
|
|
||||||
Configuration();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool readFile();
|
|
||||||
String _filePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -2,13 +2,14 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "station_utils.h"
|
#include "station_utils.h"
|
||||||
#include "aprs_is_utils.h"
|
#include "aprs_is_utils.h"
|
||||||
#include "lora_utils.h"
|
|
||||||
#include "digi_utils.h"
|
#include "digi_utils.h"
|
||||||
#include "wifi_utils.h"
|
#include "wifi_utils.h"
|
||||||
|
#include "lora_utils.h"
|
||||||
#include "gps_utils.h"
|
#include "gps_utils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern uint32_t lastScreenOn;
|
extern uint32_t lastScreenOn;
|
||||||
extern String iGateBeaconPacket;
|
extern String iGateBeaconPacket;
|
||||||
@@ -19,66 +20,154 @@ extern String fourthLine;
|
|||||||
extern String fifthLine;
|
extern String fifthLine;
|
||||||
extern String sixthLine;
|
extern String sixthLine;
|
||||||
extern String seventhLine;
|
extern String seventhLine;
|
||||||
|
extern bool backUpDigiMode;
|
||||||
|
|
||||||
|
|
||||||
namespace DIGI_Utils {
|
namespace DIGI_Utils {
|
||||||
|
|
||||||
String generateDigiRepeatedPacket(String packet, String callsign) {
|
String buildPacket(const String& path, const String& packet, bool thirdParty, bool crossFreq) {
|
||||||
String sender, temp0, tocall, path;
|
if (!crossFreq) {
|
||||||
sender = packet.substring(0,packet.indexOf(">"));
|
String packetToRepeat = packet.substring(0, packet.indexOf(",") + 1);
|
||||||
temp0 = packet.substring(packet.indexOf(">")+1,packet.indexOf(":"));
|
String tempPath = path;
|
||||||
if (temp0.indexOf(",") > 2) {
|
|
||||||
tocall = temp0.substring(0,temp0.indexOf(","));
|
if (path.indexOf("WIDE1-1") != -1 && (Config.digi.mode == 2 || Config.digi.mode == 3)) {
|
||||||
path = temp0.substring(temp0.indexOf(",")+1,temp0.indexOf(":"));
|
tempPath.replace("WIDE1-1", Config.callsign + "*");
|
||||||
if (path.indexOf("WIDE1-")>=0) {
|
} else if (path.indexOf("WIDE2-") != -1 && Config.digi.mode == 3) {
|
||||||
String hop = path.substring(path.indexOf("WIDE1-")+6, path.indexOf("WIDE1-")+7);
|
if (path.indexOf(",WIDE1*") != -1) {
|
||||||
if (hop.toInt()>=1 && hop.toInt()<=7) {
|
tempPath.remove(path.indexOf(",WIDE1*"), 7);
|
||||||
if (hop.toInt()==1) {
|
}
|
||||||
path.replace("WIDE1-1", callsign + "*");
|
if (path.indexOf("*") != -1) {
|
||||||
} else {
|
tempPath.remove(path.indexOf("*"), 1);
|
||||||
path.replace("WIDE1-" + hop , callsign + "*,WIDE1-" + String(hop.toInt()-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String generateDigipeatedPacket(const String& packet, bool thirdParty){
|
||||||
|
String temp;
|
||||||
|
if (thirdParty) { // only header is used
|
||||||
|
const String& header = packet.substring(0, packet.indexOf(":}"));
|
||||||
|
temp = header.substring(header.indexOf(">") + 1);
|
||||||
|
} else {
|
||||||
|
temp = packet.substring(packet.indexOf(">") + 1, packet.indexOf(":"));
|
||||||
|
}
|
||||||
|
if (temp.indexOf(",") > 2) { // checks for path
|
||||||
|
const String& path = temp.substring(temp.indexOf(",") + 1); // after tocall
|
||||||
|
if (Config.digi.mode == 2 || backUpDigiMode) {
|
||||||
|
if (path.indexOf("WIDE1-1") != - 1) {
|
||||||
|
return buildPacket(path, packet, thirdParty, false);
|
||||||
|
} else if (path.indexOf("WIDE1-1") == -1 && (abs(Config.loramodule.txFreq - Config.loramodule.rxFreq) >= 125000)) { // CrossFreq Digi
|
||||||
|
return buildPacket(path, packet, thirdParty, true);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} else if (Config.digi.mode == 3) {
|
||||||
|
if (path.indexOf("WIDE1-1") != -1 || path.indexOf("WIDE2-") != -1) {
|
||||||
|
int wide1Index = path.indexOf("WIDE1-1");
|
||||||
|
int wide2Index = path.indexOf("WIDE2-");
|
||||||
|
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
String repeatedPacket = sender + ">" + tocall + "," + path + packet.substring(packet.indexOf(":"));
|
return "";
|
||||||
return repeatedPacket;
|
} 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 {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return "";
|
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 {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processPacket(String packet) {
|
void processLoRaPacket(const String& packet) {
|
||||||
String loraPacket;
|
if (packet.indexOf("NOGATE") == -1) {
|
||||||
if (packet != "") {
|
bool thirdPartyPacket = false;
|
||||||
Serial.print("Received Lora Packet : " + String(packet));
|
String temp, Sender;
|
||||||
if ((packet.substring(0, 3) == "\x3c\xff\x01") && (packet.indexOf("NOGATE") == -1)) {
|
int firstColonIndex = packet.indexOf(":");
|
||||||
Serial.println(" ---> APRS LoRa Packet");
|
if (firstColonIndex > 5 && firstColonIndex < (packet.length() - 1) && packet[firstColonIndex + 1] == '}' && packet.indexOf("TCPIP") > 0) { // 3rd Party
|
||||||
String sender = packet.substring(3,packet.indexOf(">"));
|
thirdPartyPacket = true;
|
||||||
STATION_Utils::updateLastHeard(sender);
|
temp = packet.substring(packet.indexOf(":}") + 2);
|
||||||
STATION_Utils::updatePacketBuffer(packet);
|
Sender = temp.substring(0, temp.indexOf(">"));
|
||||||
Utils::typeOfPacket(packet.substring(3), "Digi");
|
} else {
|
||||||
if (packet.indexOf("WIDE1-") > 10 && Config.digi.mode == 2) { // If should repeat packet (WIDE1 Digi)
|
temp = packet.substring(3);
|
||||||
loraPacket = generateDigiRepeatedPacket(packet.substring(3), Config.callsign);
|
Sender = packet.substring(3, packet.indexOf(">"));
|
||||||
if (loraPacket != "") {
|
}
|
||||||
delay(500);
|
if (Sender != Config.callsign) { // Avoid listening to own packets
|
||||||
Serial.println(loraPacket);
|
if (!thirdPartyPacket && !Utils::checkValidCallsign(Sender)) {
|
||||||
LoRa_Utils::sendNewPacket("APRS", loraPacket);
|
return;
|
||||||
display_toggle(true);
|
}
|
||||||
lastScreenOn = millis();
|
if (STATION_Utils::check25SegBuffer(Sender, temp.substring(temp.indexOf(":") + 2)) || Config.lowPowerMode) {
|
||||||
|
STATION_Utils::updateLastHeard(Sender);
|
||||||
|
Utils::typeOfPacket(temp, 2); // Digi
|
||||||
|
bool queryMessage = false;
|
||||||
|
if (temp.indexOf("::") > 10) { // it's a message
|
||||||
|
String AddresseeAndMessage = temp.substring(temp.indexOf("::") + 2);
|
||||||
|
String Addressee = AddresseeAndMessage.substring(0, AddresseeAndMessage.indexOf(":"));
|
||||||
|
Addressee.trim();
|
||||||
|
if (Addressee == Config.callsign) { // it's a message for me!
|
||||||
|
queryMessage = APRS_IS_Utils::processReceivedLoRaMessage(Sender, AddresseeAndMessage, thirdPartyPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!queryMessage) {
|
||||||
|
String loraPacket = generateDigipeatedPacket(packet.substring(3), thirdPartyPacket);
|
||||||
|
if (loraPacket != "") {
|
||||||
|
if (Config.lowPowerMode) {
|
||||||
|
LoRa_Utils::sendNewPacket(loraPacket);
|
||||||
|
} else {
|
||||||
|
STATION_Utils::addToOutputPacketBuffer(loraPacket);
|
||||||
|
}
|
||||||
|
displayToggle(true);
|
||||||
|
lastScreenOn = millis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Serial.println(" ---> LoRa Packet Ignored (first 3 bytes or NOGATE)\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(String packet) {
|
void checkEcoMode() {
|
||||||
processPacket(packet);
|
if (Config.digi.ecoMode) {
|
||||||
|
Config.display.alwaysOn = false;
|
||||||
|
Config.display.timeout = 0;
|
||||||
|
setCpuFrequencyMhz(10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef DIGI_UTILS_H_
|
|
||||||
#define DIGI_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace DIGI_Utils {
|
|
||||||
|
|
||||||
String generateDigiRepeatedPacket(String packet, String callsign);
|
|
||||||
void processPacket(String packet);
|
|
||||||
void loop(String packet);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,165 +1,282 @@
|
|||||||
#include <Adafruit_SSD1306.h>
|
|
||||||
#include <Adafruit_GFX.h>
|
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "pins_config.h"
|
#include "board_pinout.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
||||||
|
|
||||||
extern Configuration Config;
|
#ifdef HAS_DISPLAY
|
||||||
|
#ifdef HAS_TFT
|
||||||
|
#include <TFT_eSPI.h>
|
||||||
|
|
||||||
void setup_display() {
|
TFT_eSPI tft = TFT_eSPI();
|
||||||
Wire.begin(OLED_SDA, OLED_SCL);
|
TFT_eSprite sprite = TFT_eSprite(&tft);
|
||||||
|
|
||||||
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
|
#ifdef HELTEC_WIRELESS_TRACKER
|
||||||
Serial.println(F("SSD1306 allocation failed"));
|
#define bigSizeFont 2
|
||||||
for(;;); // Don't proceed, loop forever
|
#define smallSizeFont 1
|
||||||
}
|
#define lineSpacing 10
|
||||||
if (Config.display.turn180) {
|
#endif
|
||||||
display.setRotation(2);
|
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
|
||||||
}
|
#define bigSizeFont 5
|
||||||
display.clearDisplay();
|
#define smallSizeFont 2
|
||||||
display.setTextColor(WHITE);
|
#define lineSpacing 25
|
||||||
display.setTextSize(1);
|
#endif
|
||||||
display.setCursor(0, 0);
|
uint16_t redColor = 0xc8a2;
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
#else
|
||||||
display.ssd1306_command(1);
|
#ifdef HAS_EPAPER
|
||||||
display.display();
|
#include <heltec-eink-modules.h>
|
||||||
delay(1000);
|
#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
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern Configuration Config;
|
||||||
|
|
||||||
|
bool displayFound = false;
|
||||||
|
|
||||||
|
void displaySetup() {
|
||||||
|
#ifdef HAS_DISPLAY
|
||||||
|
delay(500);
|
||||||
|
#ifdef HAS_TFT
|
||||||
|
tft.init();
|
||||||
|
tft.begin();
|
||||||
|
if (Config.display.turn180) {
|
||||||
|
tft.setRotation(3);
|
||||||
|
} else {
|
||||||
|
tft.setRotation(1);
|
||||||
|
}
|
||||||
|
pinMode(TFT_BL, OUTPUT);
|
||||||
|
digitalWrite(TFT_BL, HIGH);
|
||||||
|
tft.setTextFont(0);
|
||||||
|
tft.fillScreen(TFT_BLACK);
|
||||||
|
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
|
||||||
|
sprite.createSprite(320,240);
|
||||||
|
#else
|
||||||
|
sprite.createSprite(160,80);
|
||||||
|
#endif
|
||||||
|
#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 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) {
|
||||||
if (toggle) {
|
#ifdef HAS_DISPLAY
|
||||||
display.ssd1306_command(SSD1306_DISPLAYON);
|
if (toggle) {
|
||||||
} else {
|
#ifdef HAS_TFT
|
||||||
display.ssd1306_command(SSD1306_DISPLAYOFF);
|
digitalWrite(TFT_BL, HIGH);
|
||||||
}
|
#else
|
||||||
|
#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
|
||||||
|
#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
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_display(String line1, int wait) {
|
void displayShow(const String& header, const String& line1, const String& line2, const String& line3, int wait) {
|
||||||
display.clearDisplay();
|
#ifdef HAS_DISPLAY
|
||||||
display.setTextColor(WHITE);
|
const String* const lines[] = {&line1, &line2, &line3};
|
||||||
display.setTextSize(1);
|
#ifdef HAS_TFT
|
||||||
display.setCursor(0, 0);
|
sprite.fillSprite(TFT_BLACK);
|
||||||
display.println(line1);
|
#if defined(HELTEC_WIRELESS_TRACKER)
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
sprite.fillRect(0, 0, 160, 19, redColor);
|
||||||
display.ssd1306_command(1);
|
#endif
|
||||||
display.display();
|
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
|
||||||
delay(wait);
|
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++) {
|
||||||
|
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprite.pushSprite(0,0);
|
||||||
|
#else
|
||||||
|
#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(String line1, String line2, 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) {
|
||||||
display.clearDisplay();
|
#ifdef HAS_DISPLAY
|
||||||
display.setTextColor(WHITE);
|
const String* const lines[] = {&line1, &line2, &line3, &line4, &line5, &line6};
|
||||||
display.setTextSize(1);
|
#ifdef HAS_TFT
|
||||||
display.setCursor(0, 0);
|
sprite.fillSprite(TFT_BLACK);
|
||||||
display.println(line1);
|
#if defined(HELTEC_WIRELESS_TRACKER)
|
||||||
display.setCursor(0, 8);
|
sprite.fillRect(0, 0, 160, 19, redColor);
|
||||||
display.println(line2);
|
#endif
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
#if defined(TTGO_T_DECK_GPS) || defined(TTGO_T_DECK_PLUS)
|
||||||
display.ssd1306_command(1);
|
sprite.fillRect(0, 0, 320, 43, redColor);
|
||||||
display.display();
|
#endif
|
||||||
delay(wait);
|
sprite.setTextFont(0);
|
||||||
}
|
sprite.setTextSize(bigSizeFont);
|
||||||
|
sprite.setTextColor(TFT_WHITE, redColor);
|
||||||
|
sprite.drawString(header, 3, 3);
|
||||||
|
|
||||||
void show_display(String line1, String line2, String line3, int wait) {
|
sprite.setTextSize(smallSizeFont);
|
||||||
display.clearDisplay();
|
sprite.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
display.setTextColor(WHITE);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(0, 0);
|
|
||||||
display.println(line1);
|
|
||||||
display.setCursor(0, 8);
|
|
||||||
display.println(line2);
|
|
||||||
display.setCursor(0, 16);
|
|
||||||
display.println(line3);
|
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
|
||||||
display.ssd1306_command(1);
|
|
||||||
display.display();
|
|
||||||
delay(wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, int wait) {
|
for (int i = 0; i < 6; i++) {
|
||||||
display.clearDisplay();
|
sprite.drawString(*lines[i], 3, (lineSpacing * (2 + i)) - 2);
|
||||||
display.setTextColor(WHITE);
|
}
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(0, 0);
|
|
||||||
display.println(line1);
|
|
||||||
display.setCursor(0, 8);
|
|
||||||
display.println(line2);
|
|
||||||
display.setCursor(0, 16);
|
|
||||||
display.println(line3);
|
|
||||||
display.setCursor(0, 24);
|
|
||||||
display.println(line4);
|
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
|
||||||
display.ssd1306_command(1);
|
|
||||||
display.display();
|
|
||||||
delay(wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, int wait) {
|
sprite.pushSprite(0,0);
|
||||||
display.clearDisplay();
|
#else
|
||||||
display.setTextColor(WHITE);
|
#ifdef HAS_EPAPER
|
||||||
display.setTextSize(1);
|
lastEpaperText = header + line1 + line2 + line3 + line4 + line5 + line6;
|
||||||
display.setCursor(0, 0);
|
display.clearMemory();
|
||||||
display.println(line1);
|
display.setCursor(5,10);
|
||||||
display.setCursor(0, 8);
|
display.setFont(&FreeSansBold9pt7b);
|
||||||
display.println(line2);
|
display.println(header);
|
||||||
display.setCursor(0, 16);
|
display.setFont(NULL);
|
||||||
display.println(line3);
|
for (int i = 0; i < 6; i++) {
|
||||||
display.setCursor(0, 24);
|
display.setCursor(0, 25 + (14 * i));
|
||||||
display.println(line4);
|
display.println(*lines[i]);
|
||||||
display.setCursor(0, 32);
|
}
|
||||||
display.println(line5);
|
display.update();
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
#else
|
||||||
display.ssd1306_command(1);
|
if (displayFound) {
|
||||||
display.display();
|
display.clearDisplay();
|
||||||
delay(wait);
|
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||||
}
|
display.setTextColor(SH110X_WHITE);
|
||||||
|
#else
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, String line6, int wait) {
|
display.setTextColor(WHITE);
|
||||||
display.clearDisplay();
|
#endif
|
||||||
display.setTextColor(WHITE);
|
display.setTextSize(2);
|
||||||
display.setTextSize(1);
|
display.setCursor(0, 0);
|
||||||
display.setCursor(0, 0);
|
display.println(header);
|
||||||
display.println(line1);
|
display.setTextSize(1);
|
||||||
display.setCursor(0, 8);
|
for (int i = 0; i < 6; i++) {
|
||||||
display.println(line2);
|
display.setCursor(0, 16 + (8 * i));
|
||||||
display.setCursor(0, 16);
|
display.println(*lines[i]);
|
||||||
display.println(line3);
|
}
|
||||||
display.setCursor(0, 24);
|
#if defined(TTGO_T_Beam_S3_SUPREME_V3)
|
||||||
display.println(line4);
|
display.setContrast(1);
|
||||||
display.setCursor(0, 32);
|
#else
|
||||||
display.println(line5);
|
display.ssd1306_command(SSD1306_SETCONTRAST);
|
||||||
display.setCursor(0, 40);
|
display.ssd1306_command(1);
|
||||||
display.println(line6);
|
#endif
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
display.display();
|
||||||
display.ssd1306_command(1);
|
}
|
||||||
display.display();
|
#endif
|
||||||
delay(wait);
|
#endif
|
||||||
}
|
delay(wait);
|
||||||
|
#endif
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, String line6, String line7, int wait) {
|
|
||||||
display.clearDisplay();
|
|
||||||
display.setTextColor(WHITE);
|
|
||||||
display.setTextSize(2);
|
|
||||||
display.setCursor(0, 0);
|
|
||||||
display.println(line1);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(0, 16);
|
|
||||||
display.println(line2);
|
|
||||||
display.setCursor(0, 24);
|
|
||||||
display.println(line3);
|
|
||||||
display.setCursor(0, 32);
|
|
||||||
display.println(line4);
|
|
||||||
display.setCursor(0, 40);
|
|
||||||
display.println(line5);
|
|
||||||
display.setCursor(0, 48);
|
|
||||||
display.println(line6);
|
|
||||||
display.setCursor(0, 56);
|
|
||||||
display.println(line7);
|
|
||||||
display.ssd1306_command(SSD1306_SETCONTRAST);
|
|
||||||
display.ssd1306_command(1);
|
|
||||||
display.display();
|
|
||||||
delay(wait);
|
|
||||||
}
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef DISPLAY_H_
|
|
||||||
#define DISPLAY_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#define SCREEN_WIDTH 128 // OLED display width, in pixels
|
|
||||||
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
|
|
||||||
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
|
|
||||||
|
|
||||||
|
|
||||||
void setup_display();
|
|
||||||
void display_toggle(bool toggle);
|
|
||||||
|
|
||||||
void show_display(String line1, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, String line3, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, String line6, int wait = 0);
|
|
||||||
void show_display(String line1, String line2, String line3, String line4, String line5, String line6, String line7, int wait = 0);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,179 +1,240 @@
|
|||||||
#include <TinyGPS++.h>
|
#include <TinyGPS++.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "board_pinout.h"
|
||||||
#include "gps_utils.h"
|
#include "gps_utils.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
extern Configuration Config;
|
#ifdef GPS_BAUDRATE
|
||||||
extern WiFiClient espClient;
|
#define GPS_BAUD GPS_BAUDRATE
|
||||||
String distance;
|
#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 {
|
namespace GPS_Utils {
|
||||||
|
|
||||||
String double2string(double n, int ndec) {
|
String getiGateLoRaBeaconPacket() {
|
||||||
String r = "";
|
return iGateLoRaBeaconPacket;
|
||||||
if (n>-1 && n<0) {
|
|
||||||
r = "-";
|
|
||||||
}
|
|
||||||
int v = n;
|
|
||||||
r += v;
|
|
||||||
r += '.';
|
|
||||||
for (int i=0;i<ndec;i++) {
|
|
||||||
n -= v;
|
|
||||||
n = 10 * abs(n);
|
|
||||||
v = n;
|
|
||||||
r += v;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String processLatitudeAPRS(double lat) {
|
char *ax25_base91enc(char *s, uint8_t n, uint32_t v) {
|
||||||
String degrees = double2string(lat,6);
|
for(s += n, *s = '\0'; n; n--) {
|
||||||
String north_south, latitude, convDeg3;
|
*(--s) = v % 91 + 33;
|
||||||
float convDeg, convDeg2;
|
v /= 91;
|
||||||
|
|
||||||
if (abs(degrees.toFloat()) < 10) {
|
|
||||||
latitude += "0";
|
|
||||||
}
|
}
|
||||||
Serial.println(latitude);
|
return(s);
|
||||||
if (degrees.indexOf("-") == 0) {
|
|
||||||
north_south = "S";
|
|
||||||
latitude += degrees.substring(1,degrees.indexOf("."));
|
|
||||||
} else {
|
|
||||||
north_south = "N";
|
|
||||||
latitude += degrees.substring(0,degrees.indexOf("."));
|
|
||||||
}
|
|
||||||
convDeg = abs(degrees.toFloat()) - abs(int(degrees.toFloat()));
|
|
||||||
convDeg2 = (convDeg * 60)/100;
|
|
||||||
convDeg3 = String(convDeg2,6);
|
|
||||||
latitude += convDeg3.substring(convDeg3.indexOf(".")+1,convDeg3.indexOf(".")+3) + "." + convDeg3.substring(convDeg3.indexOf(".")+3,convDeg3.indexOf(".")+5);
|
|
||||||
latitude += north_south;
|
|
||||||
return latitude;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String processLongitudeAPRS(double lon) {
|
float roundToTwoDecimals(float degrees) {
|
||||||
String degrees = double2string(lon,6);
|
return round(degrees * 100) / 100;
|
||||||
String east_west, longitude, convDeg3;
|
|
||||||
float convDeg, convDeg2;
|
|
||||||
|
|
||||||
if (abs(degrees.toFloat()) < 100) {
|
|
||||||
longitude += "0";
|
|
||||||
}
|
|
||||||
if (abs(degrees.toFloat()) < 10) {
|
|
||||||
longitude += "0";
|
|
||||||
}
|
|
||||||
if (degrees.indexOf("-") == 0) {
|
|
||||||
east_west = "W";
|
|
||||||
longitude += degrees.substring(1,degrees.indexOf("."));
|
|
||||||
} else {
|
|
||||||
east_west = "E";
|
|
||||||
longitude += degrees.substring(0,degrees.indexOf("."));
|
|
||||||
}
|
|
||||||
convDeg = abs(degrees.toFloat()) - abs(int(degrees.toFloat()));
|
|
||||||
convDeg2 = (convDeg * 60)/100;
|
|
||||||
convDeg3 = String(convDeg2,6);
|
|
||||||
longitude += convDeg3.substring(convDeg3.indexOf(".")+1,convDeg3.indexOf(".")+3) + "." + convDeg3.substring(convDeg3.indexOf(".")+3,convDeg3.indexOf(".")+5);
|
|
||||||
longitude += east_west;
|
|
||||||
return longitude;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateBeacon() {
|
String encodeGPS(float latitude, float longitude, const String& overlay, const String& symbol) {
|
||||||
String stationLatitude = processLatitudeAPRS(Config.beacon.latitude);
|
String encodedData = overlay;
|
||||||
String stationLongitude = processLongitudeAPRS(Config.beacon.longitude);
|
uint32_t aprs_lat, aprs_lon;
|
||||||
|
|
||||||
String beaconPacket = Config.callsign + ">APLRG1," + Config.beacon.path;
|
float processedLatitude = latitude;
|
||||||
|
float processedLongitude = longitude;
|
||||||
|
if (Config.beacon.gpsActive && Config.beacon.gpsAmbiguity) {
|
||||||
|
processedLatitude = roundToTwoDecimals(latitude);
|
||||||
|
processedLongitude = roundToTwoDecimals(longitude);
|
||||||
|
}
|
||||||
|
|
||||||
if (Config.aprs_is.active && Config.digi.mode == 0) { // If APRSIS enabled and Digi disabled
|
aprs_lat = 900000000 - processedLatitude * 10000000;
|
||||||
beaconPacket += ",qAC";
|
aprs_lat = aprs_lat / 26 - aprs_lat / 2710 + aprs_lat / 15384615;
|
||||||
} else {}
|
aprs_lon = 900000000 + processedLongitude * 10000000 / 2;
|
||||||
|
aprs_lon = aprs_lon / 26 - aprs_lon / 2710 + aprs_lon / 15384615;
|
||||||
|
|
||||||
beaconPacket += ":=" + stationLatitude + Config.beacon.overlay + stationLongitude + Config.beacon.symbol;
|
String Ns, Ew, helper;
|
||||||
beaconPacket += Config.beacon.comment;
|
if(processedLatitude < 0) { Ns = "S"; } else { Ns = "N"; }
|
||||||
|
if(processedLatitude < 0) { processedLatitude = -processedLatitude; }
|
||||||
|
|
||||||
return beaconPacket;
|
if(processedLongitude < 0) { Ew = "W"; } else { Ew = "E"; }
|
||||||
|
if(processedLongitude < 0) { processedLongitude = -processedLongitude; }
|
||||||
|
|
||||||
|
char helper_base91[] = {"0000\0"};
|
||||||
|
int i;
|
||||||
|
ax25_base91enc(helper_base91, 4, aprs_lat);
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
encodedData += helper_base91[i];
|
||||||
|
}
|
||||||
|
ax25_base91enc(helper_base91, 4, aprs_lon);
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
encodedData += helper_base91[i];
|
||||||
|
}
|
||||||
|
encodedData += symbol;
|
||||||
|
encodedData += " ";
|
||||||
|
encodedData += "\x47";
|
||||||
|
return encodedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateiGateLoRaBeacon() {
|
void generateBeaconFirstPart() {
|
||||||
String stationLatitude = processLatitudeAPRS(Config.beacon.latitude);
|
String beaconPacket = Config.callsign;
|
||||||
String stationLongitude = processLongitudeAPRS(Config.beacon.longitude);
|
beaconPacket += ">APLRG1";
|
||||||
|
if (Config.beacon.path.indexOf("WIDE") == 0) {
|
||||||
String beaconPacket = Config.callsign + ">APLRG1," + Config.beacon.path + ":=" + stationLatitude + Config.beacon.overlay + stationLongitude + Config.beacon.symbol;
|
beaconPacket += ",";
|
||||||
|
beaconPacket += Config.beacon.path;
|
||||||
|
}
|
||||||
|
iGateBeaconPacket = beaconPacket;
|
||||||
|
iGateBeaconPacket += ",qAC:!";
|
||||||
|
iGateLoRaBeaconPacket = beaconPacket;
|
||||||
|
iGateLoRaBeaconPacket += ":!";
|
||||||
|
}
|
||||||
|
|
||||||
return beaconPacket;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
double calculateDistanceTo(double latitude, double longitude) {
|
double calculateDistanceTo(double latitude, double longitude) {
|
||||||
return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0;
|
return TinyGPSPlus::distanceBetween(Config.beacon.latitude,Config.beacon.longitude, latitude, longitude) / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String decodeEncodedGPS(String packet) {
|
String decodeEncodedGPS(const String& packet) {
|
||||||
String GPSPacket = packet.substring(packet.indexOf(":!")+3);
|
int indexOfExclamation = packet.indexOf(":!");
|
||||||
String encodedLatitude = GPSPacket.substring(0,4);
|
int indexOfEqual = packet.indexOf(":=");
|
||||||
String encodedLongtitude = GPSPacket.substring(4,8);
|
|
||||||
|
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);
|
||||||
|
|
||||||
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);
|
|
||||||
distance = String(calculateDistanceTo(decodedLatitude, decodedLongitude),1);
|
distance = String(calculateDistanceTo(decodedLatitude, decodedLongitude),1);
|
||||||
return String(decodedLatitude,5) + "N / " + String(decodedLongitude,5) + "E / " + distance + "km";
|
|
||||||
|
String decodedGPS = String(decodedLatitude,5);
|
||||||
|
decodedGPS += "N / ";
|
||||||
|
decodedGPS += String(decodedLongitude,5);
|
||||||
|
decodedGPS += "E / ";
|
||||||
|
decodedGPS += distance;
|
||||||
|
decodedGPS += "km";
|
||||||
|
|
||||||
|
String comment = GPSPacket.substring(12);
|
||||||
|
if (comment != "") {
|
||||||
|
decodedGPS += " / ";
|
||||||
|
decodedGPS += comment;
|
||||||
|
}
|
||||||
|
return decodedGPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getReceivedGPS(String packet) {
|
String getReceivedGPS(const String& packet) {
|
||||||
|
int indexOfExclamation = packet.indexOf(":!");
|
||||||
|
int indexOfEqual = packet.indexOf(":=");
|
||||||
|
int indexOfAt = packet.indexOf(":@");
|
||||||
|
|
||||||
String infoGPS;
|
String infoGPS;
|
||||||
if (packet.indexOf(":!") > 10) {
|
if (indexOfExclamation > 10) {
|
||||||
infoGPS = packet.substring(packet.indexOf(":!")+2);
|
infoGPS = packet.substring(indexOfExclamation + 2);
|
||||||
} else if (packet.indexOf(":=") > 10) {
|
} else if (indexOfEqual > 10) {
|
||||||
infoGPS = packet.substring(packet.indexOf(":=")+2);
|
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);
|
|
||||||
String Longitude = infoGPS.substring(9,18);
|
|
||||||
|
|
||||||
float convertedLatitude, convertedLongitude;
|
String Latitude = infoGPS.substring(0,8); // First 8 characters are Latitude
|
||||||
String firstLatPart = Latitude.substring(0,2);
|
float convertedLatitude = Latitude.substring(0,2).toFloat(); // First 2 digits (Degrees)
|
||||||
String secondLatPart = Latitude.substring(2,4);
|
convertedLatitude += Latitude.substring(2,4).toFloat() / 60; // Next 2 digits (Minutes)
|
||||||
String thirdLatPart = Latitude.substring(Latitude.indexOf(".")+1,Latitude.indexOf(".")+3);
|
convertedLatitude += Latitude.substring(Latitude.indexOf(".") + 1, Latitude.indexOf(".") + 3).toFloat() / (60*100);
|
||||||
String firstLngPart = Longitude.substring(0,3);
|
if (Latitude.endsWith("S")) convertedLatitude = -convertedLatitude; // Handle Southern Hemisphere
|
||||||
String secondLngPart = Longitude.substring(3,5);
|
|
||||||
String thirdLngPart = Longitude.substring(Longitude.indexOf(".")+1,Longitude.indexOf(".")+3);
|
String Longitude = infoGPS.substring(9,18); // Next 9 characters are Longitude
|
||||||
convertedLatitude = firstLatPart.toFloat() + (secondLatPart.toFloat()/60) + (thirdLatPart.toFloat()/(60*100));
|
float convertedLongitude = Longitude.substring(0,3).toFloat(); // First 3 digits (Degrees)
|
||||||
convertedLongitude = firstLngPart.toFloat() + (secondLngPart.toFloat()/60) + (thirdLngPart.toFloat()/(60*100));
|
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
|
||||||
|
|
||||||
String LatSign = String(Latitude[7]);
|
|
||||||
String LngSign = String(Longitude[8]);
|
|
||||||
if (LatSign == "S") {
|
|
||||||
convertedLatitude = -convertedLatitude;
|
|
||||||
}
|
|
||||||
if (LngSign == "W") {
|
|
||||||
convertedLongitude = -convertedLongitude;
|
|
||||||
}
|
|
||||||
distance = String(calculateDistanceTo(convertedLatitude, convertedLongitude),1);
|
distance = String(calculateDistanceTo(convertedLatitude, convertedLongitude),1);
|
||||||
return String(convertedLatitude,5) + "N / " + String(convertedLongitude,5) + "E / " + distance + "km";
|
|
||||||
|
String decodedGPS = String(convertedLatitude,5);
|
||||||
|
decodedGPS += "N / ";
|
||||||
|
decodedGPS += String(convertedLongitude,5);
|
||||||
|
decodedGPS += "E / ";
|
||||||
|
decodedGPS += distance;
|
||||||
|
decodedGPS += "km";
|
||||||
|
|
||||||
|
String comment = infoGPS.substring(19);
|
||||||
|
if (comment != "") {
|
||||||
|
decodedGPS += " / ";
|
||||||
|
decodedGPS += comment;
|
||||||
|
}
|
||||||
|
return decodedGPS;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDistance(String packet) {
|
String getDistanceAndComment(const String& packet) {
|
||||||
int encodedBytePosition = 0;
|
int indexOfAt = packet.indexOf(":@");
|
||||||
if (packet.indexOf(":!") > 10) {
|
if (indexOfAt > 10) {
|
||||||
encodedBytePosition = packet.indexOf(":!") + 14;
|
return getReceivedGPS(packet);
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
} 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) {
|
||||||
|
gpsSerial.begin(GPS_BAUD, SERIAL_8N1, GPS_TX, GPS_RX);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
generateBeacons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getData() {
|
||||||
|
while (gpsSerial.available() > 0) {
|
||||||
|
gps.encode(gpsSerial.read());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
#ifndef GPS_UTILS_H_
|
|
||||||
#define GPS_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace GPS_Utils {
|
|
||||||
|
|
||||||
String double2string(double n, int ndec);
|
|
||||||
String processLatitudeAPRS();
|
|
||||||
String processLongitudeAPRS();
|
|
||||||
String generateBeacon();
|
|
||||||
String generateiGateLoRaBeacon();
|
|
||||||
double calculateDistanceCourse(double latitude, double longitude);
|
|
||||||
String decodeEncodedGPS(String packet);
|
|
||||||
String getReceivedGPS(String packet);
|
|
||||||
String getDistance(String packet);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include "kiss_protocol.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool validateTNC2Frame(const String& tnc2FormattedFrame) {
|
||||||
|
return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validateKISSFrame(const String& kissFormattedFrame) {
|
||||||
|
return kissFormattedFrame.charAt(0) == (char)FEND && kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char)FEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeAddressAX25(String tnc2Address) {
|
||||||
|
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
||||||
|
|
||||||
|
if (tnc2Address.indexOf('-') == -1) {
|
||||||
|
if (hasBeenDigipited) {
|
||||||
|
tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tnc2Address += "-0";
|
||||||
|
}
|
||||||
|
|
||||||
|
int separatorIndex = tnc2Address.indexOf('-');
|
||||||
|
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||||
|
|
||||||
|
String kissAddress = "";
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
char addressChar;
|
||||||
|
if (tnc2Address.length() > i && i < separatorIndex) {
|
||||||
|
addressChar = tnc2Address.charAt(i);
|
||||||
|
} else {
|
||||||
|
addressChar = ' ';
|
||||||
|
}
|
||||||
|
kissAddress += (char)(addressChar << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
kissAddress += (char)((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
||||||
|
return kissAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
String decodeAddressAX25(const String& ax25Address, bool& isLast, bool isRelay) {
|
||||||
|
String address = "";
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
uint8_t currentCharacter = ax25Address.charAt(i);
|
||||||
|
currentCharacter >>= 1;
|
||||||
|
if (currentCharacter != ' ') {
|
||||||
|
address += (char)currentCharacter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto ssidChar = (uint8_t)ax25Address.charAt(6);
|
||||||
|
bool hasBeenDigipited = ssidChar & HAS_BEEN_DIGIPITED_MASK;
|
||||||
|
isLast = ssidChar & IS_LAST_ADDRESS_POSITION_MASK;
|
||||||
|
ssidChar >>= 1;
|
||||||
|
|
||||||
|
int ssid = 0b1111 & ssidChar;
|
||||||
|
|
||||||
|
if (ssid) {
|
||||||
|
address += '-';
|
||||||
|
address += ssid;
|
||||||
|
}
|
||||||
|
if (isRelay && hasBeenDigipited) {
|
||||||
|
address += '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encapsulateKISS(const String& ax25Frame, uint8_t cmd) {
|
||||||
|
String kissFrame = "";
|
||||||
|
kissFrame += (char)FEND;
|
||||||
|
kissFrame += (char)(0x0f & cmd);
|
||||||
|
|
||||||
|
for (int i = 0; i < ax25Frame.length(); ++i) {
|
||||||
|
char currentChar = ax25Frame.charAt(i);
|
||||||
|
if (currentChar == (char)FEND) {
|
||||||
|
kissFrame += (char)FESC;
|
||||||
|
kissFrame += (char)TFEND;
|
||||||
|
} else if (currentChar == (char)FESC) {
|
||||||
|
kissFrame += (char)FESC;
|
||||||
|
kissFrame += (char)TFESC;
|
||||||
|
} else {
|
||||||
|
kissFrame += currentChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kissFrame += (char)FEND; // end of frame
|
||||||
|
return kissFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String decapsulateKISS(const String& frame) {
|
||||||
|
String ax25Frame = "";
|
||||||
|
for (int i = 2; i < frame.length() - 1; ++i) {
|
||||||
|
char currentChar = frame.charAt(i);
|
||||||
|
if (currentChar == (char)FESC) {
|
||||||
|
char nextChar = frame.charAt(i + 1);
|
||||||
|
if (nextChar == (char)TFEND) {
|
||||||
|
ax25Frame += (char)FEND;
|
||||||
|
} else if (nextChar == (char)TFESC) {
|
||||||
|
ax25Frame += (char)FESC;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
ax25Frame += currentChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ax25Frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeKISS(const String& frame) {
|
||||||
|
String ax25Frame = "";
|
||||||
|
|
||||||
|
if (validateTNC2Frame(frame)) {
|
||||||
|
String address = "";
|
||||||
|
bool dstAddresWritten = false;
|
||||||
|
for (int p = 0; p <= frame.indexOf(':'); p++) {
|
||||||
|
char currentChar = frame.charAt(p);
|
||||||
|
if (currentChar == ':' || currentChar == '>' || currentChar == ',') {
|
||||||
|
if (!dstAddresWritten && (currentChar == ',' || currentChar == ':')) {
|
||||||
|
ax25Frame = encodeAddressAX25(address) + ax25Frame;
|
||||||
|
dstAddresWritten = true;
|
||||||
|
} else {
|
||||||
|
ax25Frame += encodeAddressAX25(address);
|
||||||
|
}
|
||||||
|
address = "";
|
||||||
|
} else {
|
||||||
|
address += currentChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lastAddressChar = (uint8_t)ax25Frame.charAt(ax25Frame.length() - 1);
|
||||||
|
ax25Frame.setCharAt(ax25Frame.length() - 1, (char)(lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
||||||
|
ax25Frame += (char)APRS_CONTROL_FIELD;
|
||||||
|
ax25Frame += (char)APRS_INFORMATION_FIELD;
|
||||||
|
ax25Frame += frame.substring(frame.indexOf(':') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
||||||
|
return kissFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
String decodeKISS(const String& inputFrame, bool& dataFrame) {
|
||||||
|
String frame = "";
|
||||||
|
|
||||||
|
if (validateKISSFrame(inputFrame)) {
|
||||||
|
dataFrame = inputFrame.charAt(1) == CMD_DATA;
|
||||||
|
if (dataFrame) {
|
||||||
|
String ax25Frame = decapsulateKISS(inputFrame);
|
||||||
|
bool isLast = false;
|
||||||
|
String dstAddr = decodeAddressAX25(ax25Frame.substring(0, 7), isLast, false);
|
||||||
|
String srcAddr = decodeAddressAX25(ax25Frame.substring(7, 14), isLast, false);
|
||||||
|
|
||||||
|
frame = srcAddr + ">" + dstAddr;
|
||||||
|
|
||||||
|
int digiInfoIndex = 14;
|
||||||
|
while (!isLast && digiInfoIndex + 7 < ax25Frame.length()) {
|
||||||
|
String digiAddr = decodeAddressAX25(ax25Frame.substring(digiInfoIndex, digiInfoIndex + 7), isLast, true);
|
||||||
|
frame += ',' + digiAddr;
|
||||||
|
digiInfoIndex += 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame += ':';
|
||||||
|
frame += ax25Frame.substring(digiInfoIndex + 2);
|
||||||
|
} else {
|
||||||
|
frame += inputFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
@@ -1,23 +1,42 @@
|
|||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
#include <LoRa.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "aprs_is_utils.h"
|
#include "aprs_is_utils.h"
|
||||||
|
#include "station_utils.h"
|
||||||
|
#include "board_pinout.h"
|
||||||
#include "syslog_utils.h"
|
#include "syslog_utils.h"
|
||||||
#include "pins_config.h"
|
#include "ntp_utils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
extern Configuration Config;
|
|
||||||
|
|
||||||
#if defined(HELTEC_V3) || defined(TTGO_T_Beam_V1_2_SX1262)
|
extern Configuration Config;
|
||||||
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
|
extern uint32_t lastRxTime;
|
||||||
bool transmissionFlag = true;
|
|
||||||
bool enableInterrupt = true;
|
extern std::vector<ReceivedPacket> receivedPackets;
|
||||||
|
|
||||||
|
bool operationDone = true;
|
||||||
|
bool transmitFlag = true;
|
||||||
|
|
||||||
|
#ifdef HAS_SX1262
|
||||||
|
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
|
||||||
#endif
|
#endif
|
||||||
#if defined(ESP32_DIY_1W_LoRa) || defined(TTGO_T_Beam_V1_0_SX1268)
|
#ifdef HAS_SX1268
|
||||||
SX1268 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
|
#if defined(LIGHTGATEWAY_1_0)
|
||||||
bool transmissionFlag = true;
|
SPIClass loraSPI(FSPI);
|
||||||
bool enableInterrupt = true;
|
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
|
#endif
|
||||||
|
|
||||||
int rssi, freqError;
|
int rssi, freqError;
|
||||||
@@ -27,203 +46,195 @@ float snr;
|
|||||||
namespace LoRa_Utils {
|
namespace LoRa_Utils {
|
||||||
|
|
||||||
void setFlag(void) {
|
void setFlag(void) {
|
||||||
#ifdef HAS_SX126X
|
operationDone = true;
|
||||||
transmissionFlag = true;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
#ifdef HAS_SX127X
|
#ifdef LIGHTGATEWAY_1_0
|
||||||
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
pinMode(RADIO_VCC_PIN,OUTPUT);
|
||||||
LoRa.setPins(LORA_CS, LORA_RST, LORA_IRQ);
|
digitalWrite(RADIO_VCC_PIN,HIGH);
|
||||||
long freq = Config.loramodule.rxFreq;
|
loraSPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN, RADIO_CS_PIN);
|
||||||
if (!LoRa.begin(freq)) {
|
#else
|
||||||
Serial.println("Starting LoRa failed!");
|
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
|
||||||
show_display("ERROR", "Starting LoRa failed!");
|
#endif
|
||||||
while (true) {
|
float freq = (float)Config.loramodule.rxFreq / 1000000;
|
||||||
delay(1000);
|
#if defined(RADIO_HAS_XTAL)
|
||||||
}
|
radio.XTAL = true;
|
||||||
}
|
|
||||||
LoRa.setSpreadingFactor(Config.loramodule.spreadingFactor);
|
|
||||||
LoRa.setSignalBandwidth(Config.loramodule.signalBandwidth);
|
|
||||||
LoRa.setCodingRate4(Config.loramodule.codingRate4);
|
|
||||||
LoRa.enableCrc();
|
|
||||||
LoRa.setTxPower(Config.loramodule.power);
|
|
||||||
Serial.print("init : LoRa Module ... done!");
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_SX126X
|
|
||||||
SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN);
|
|
||||||
float freq = (float)Config.loramodule.rxFreq/1000000;
|
|
||||||
int state = radio.begin(freq);
|
int state = radio.begin(freq);
|
||||||
if (state == RADIOLIB_ERR_NONE) {
|
if (state == RADIOLIB_ERR_NONE) {
|
||||||
Serial.print("Initializing SX126X LoRa Module");
|
Utils::println("Initializing LoRa Module");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("Starting LoRa failed!");
|
Utils::println("Starting LoRa failed! State: " + String(state));
|
||||||
while (true);
|
|
||||||
}
|
|
||||||
radio.setDio1Action(setFlag);
|
|
||||||
radio.setSpreadingFactor(Config.loramodule.spreadingFactor);
|
|
||||||
radio.setBandwidth(Config.loramodule.signalBandwidth);
|
|
||||||
radio.setCodingRate(Config.loramodule.codingRate4);
|
|
||||||
radio.setCRC(true);
|
|
||||||
#if defined(ESP32_DIY_1W_LoRa)
|
|
||||||
radio.setRfSwitchPins(RADIO_RXEN, RADIO_TXEN);
|
|
||||||
#endif
|
|
||||||
#if defined(HELTEC_V3) || defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2_SX1262)
|
|
||||||
state = radio.setOutputPower(Config.loramodule.power + 2); // values available: 10, 17, 22 --> if 20 in tracker_conf.json it will be updated to 22.
|
|
||||||
#endif
|
|
||||||
#ifdef ESP32_DIY_1W_LoRa_GPS
|
|
||||||
state = radio.setOutputPower(Config.loramodule.power); // max value 20 (when 20dB in setup 30dB in output as 400M30S has Low Noise Amp)
|
|
||||||
#endif
|
|
||||||
if (state == RADIOLIB_ERR_NONE) {
|
|
||||||
Serial.println("init : LoRa Module ... done!");
|
|
||||||
} else {
|
|
||||||
Serial.println("Starting LoRa failed!");
|
|
||||||
while (true);
|
while (true);
|
||||||
}
|
}
|
||||||
|
#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
|
#endif
|
||||||
|
#if defined(HAS_SX1278) || defined(HAS_SX1276)
|
||||||
|
radio.setDio0Action(setFlag, RISING);
|
||||||
|
#endif
|
||||||
|
radio.setSpreadingFactor(Config.loramodule.spreadingFactor);
|
||||||
|
float signalBandwidth = Config.loramodule.signalBandwidth/1000;
|
||||||
|
radio.setBandwidth(signalBandwidth);
|
||||||
|
radio.setCodingRate(Config.loramodule.codingRate4);
|
||||||
|
radio.setCRC(true);
|
||||||
|
|
||||||
|
#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) / 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
|
||||||
|
#if defined(HAS_SX1278) || defined(HAS_SX1276)
|
||||||
|
state = radio.setOutputPower(Config.loramodule.power); // max value 20dB for 400M30S as it has Low Noise Amp
|
||||||
|
radio.setCurrentLimit(100); // to be validated (80 , 100)?
|
||||||
|
#endif
|
||||||
|
#if (defined(HAS_SX1268) || defined(HAS_SX1262)) && !defined(HAS_1W_LORA)
|
||||||
|
state = radio.setOutputPower(Config.loramodule.power + 2); // values available: 10, 17, 22 --> if 20 in tracker_conf.json it will be updated to 22.
|
||||||
|
radio.setCurrentLimit(140);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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! State: " + String(state));
|
||||||
|
while (true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeFreqTx() {
|
void changeFreqTx() {
|
||||||
delay(500);
|
delay(500);
|
||||||
#ifdef HAS_SX127X
|
float freq = (float)Config.loramodule.txFreq / 1000000;
|
||||||
LoRa.setFrequency(Config.loramodule.txFreq);
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SX126X
|
|
||||||
float freq = (float)Config.loramodule.txFreq/1000000;
|
|
||||||
radio.setFrequency(freq);
|
radio.setFrequency(freq);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeFreqRx() {
|
void changeFreqRx() {
|
||||||
delay(500);
|
delay(500);
|
||||||
#ifdef HAS_SX127X
|
float freq = (float)Config.loramodule.rxFreq / 1000000;
|
||||||
LoRa.setFrequency(Config.loramodule.rxFreq);
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SX126X
|
|
||||||
float freq = (float)Config.loramodule.rxFreq/1000000;
|
|
||||||
radio.setFrequency(freq);
|
radio.setFrequency(freq);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendNewPacket(const String &typeOfMessage, const String &newPacket) {
|
void sendNewPacket(const String& newPacket) {
|
||||||
if (!Config.loramodule.txActive) return;
|
if (!Config.loramodule.txActive) return;
|
||||||
|
|
||||||
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
|
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
|
||||||
changeFreqTx();
|
changeFreqTx();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(HELTEC_V3) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
|
#ifdef INTERNAL_LED_PIN
|
||||||
digitalWrite(internalLedPin,HIGH);
|
if (!Config.digi.ecoMode) digitalWrite(INTERNAL_LED_PIN, HIGH);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_SX127X
|
|
||||||
LoRa.beginPacket();
|
|
||||||
LoRa.write('<');
|
|
||||||
if (typeOfMessage == "APRS") {
|
|
||||||
LoRa.write(0xFF);
|
|
||||||
} else if (typeOfMessage == "LoRa") {
|
|
||||||
LoRa.write(0xF8);
|
|
||||||
}
|
|
||||||
LoRa.write(0x01);
|
|
||||||
LoRa.write((const uint8_t *)newPacket.c_str(), newPacket.length());
|
|
||||||
LoRa.endPacket();
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SX126X
|
|
||||||
int state = radio.transmit("\x3c\xff\x01" + newPacket);
|
int state = radio.transmit("\x3c\xff\x01" + newPacket);
|
||||||
|
transmitFlag = true;
|
||||||
if (state == RADIOLIB_ERR_NONE) {
|
if (state == RADIOLIB_ERR_NONE) {
|
||||||
//Serial.println(F("success!"));
|
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||||
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
|
SYSLOG_Utils::log(3, newPacket, 0, 0.0, 0); // TX
|
||||||
Serial.println(F("too long!"));
|
}
|
||||||
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
|
Utils::print("---> LoRa Packet Tx : ");
|
||||||
Serial.println(F("timeout!"));
|
Utils::println(newPacket);
|
||||||
} else {
|
} else {
|
||||||
Serial.print(F("failed, code "));
|
Utils::print(F("failed, code "));
|
||||||
Serial.println(state);
|
Utils::println(String(state));
|
||||||
}
|
}
|
||||||
|
#ifdef INTERNAL_LED_PIN
|
||||||
|
if (!Config.digi.ecoMode) digitalWrite(INTERNAL_LED_PIN, LOW);
|
||||||
#endif
|
#endif
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(HELTEC_V3) || defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
|
|
||||||
digitalWrite(internalLedPin,LOW);
|
|
||||||
#endif
|
|
||||||
SYSLOG_Utils::log("Tx", newPacket,0,0,0);
|
|
||||||
Serial.print("---> LoRa Packet Tx : ");
|
|
||||||
Serial.println(newPacket);
|
|
||||||
|
|
||||||
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
|
if (Config.loramodule.txFreq != Config.loramodule.rxFreq) {
|
||||||
changeFreqRx();
|
changeFreqRx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String generatePacket(String aprsisPacket) {
|
/*String packetSanitization(const String& packet) {
|
||||||
String firstPart, messagePart;
|
String sanitizedPacket = packet;
|
||||||
aprsisPacket.trim();
|
if (packet.indexOf("\0") > 0) {
|
||||||
firstPart = aprsisPacket.substring(0, aprsisPacket.indexOf(","));
|
sanitizedPacket.replace("\0", "");
|
||||||
messagePart = aprsisPacket.substring(aprsisPacket.indexOf("::")+2);
|
}
|
||||||
return firstPart + ",TCPIP,WIDE1-1," + Config.callsign + "::" + messagePart;
|
if (packet.indexOf("\r") > 0) {
|
||||||
|
sanitizedPacket.replace("\r", "");
|
||||||
|
}
|
||||||
|
if (packet.indexOf("\n") > 0) {
|
||||||
|
sanitizedPacket.replace("\n", "");
|
||||||
|
}
|
||||||
|
return sanitizedPacket;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void startReceive() {
|
||||||
|
radio.startReceive();
|
||||||
}
|
}
|
||||||
|
|
||||||
String packetSanitization(String packet) {
|
String receivePacket() {
|
||||||
Serial.println(packet);
|
String packet = "";
|
||||||
if (packet.indexOf("\0")>0) {
|
if (operationDone || Config.lowPowerMode) {
|
||||||
packet.replace("\0","");
|
operationDone = false;
|
||||||
}
|
if (transmitFlag && !Config.lowPowerMode) {
|
||||||
if (packet.indexOf("\r")>0) {
|
radio.startReceive();
|
||||||
packet.replace("\r","");
|
transmitFlag = false;
|
||||||
}
|
} else {
|
||||||
if (packet.indexOf("\n")>0) {
|
int state = radio.readData(packet);
|
||||||
packet.replace("\n","");
|
if (state == RADIOLIB_ERR_NONE) {
|
||||||
|
if (packet != "") {
|
||||||
|
|
||||||
|
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.lowPowerMode && !Config.digi.ecoMode) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
freqError = radio.getFrequencyError();
|
||||||
|
Utils::println(F("CRC error!"));
|
||||||
|
if (Config.syslog.active && WiFi.status() == WL_CONNECTED) {
|
||||||
|
SYSLOG_Utils::log(0, packet, rssi, snr, freqError); // CRC
|
||||||
|
}
|
||||||
|
packet = "";
|
||||||
|
} else {
|
||||||
|
Utils::print(F("failed, code "));
|
||||||
|
Utils::println(String(state));
|
||||||
|
packet = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
String receivePacket() {
|
void sleepRadio() {
|
||||||
String loraPacket = "";
|
radio.sleep();
|
||||||
#ifdef HAS_SX127X
|
|
||||||
int packetSize = LoRa.parsePacket();
|
|
||||||
if (packetSize) {
|
|
||||||
while (LoRa.available()) {
|
|
||||||
int inChar = LoRa.read();
|
|
||||||
loraPacket += (char)inChar;
|
|
||||||
}
|
|
||||||
rssi = LoRa.packetRssi();
|
|
||||||
snr = LoRa.packetSnr();
|
|
||||||
freqError = LoRa.packetFrequencyError();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_SX126X
|
|
||||||
if (transmissionFlag) {
|
|
||||||
transmissionFlag = false;
|
|
||||||
radio.startReceive();
|
|
||||||
int state = radio.readData(loraPacket);
|
|
||||||
if (state == RADIOLIB_ERR_NONE) {
|
|
||||||
Serial.println("LoRa Rx ---> " + loraPacket);
|
|
||||||
rssi = radio.getRSSI();
|
|
||||||
snr = radio.getSNR();
|
|
||||||
freqError = radio.getFrequencyError();
|
|
||||||
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
|
|
||||||
// timeout occurred while waiting for a packet
|
|
||||||
} else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
|
|
||||||
Serial.println(F("CRC error!"));
|
|
||||||
} else {
|
|
||||||
Serial.print(F("failed, code "));
|
|
||||||
Serial.println(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((loraPacket.indexOf("\0")!=-1) || (loraPacket.indexOf("\r")!=-1) || (loraPacket.indexOf("\n")!=-1)) {
|
|
||||||
loraPacket = packetSanitization(loraPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef TextSerialOutputForApp
|
|
||||||
if (loraPacket!="") {
|
|
||||||
Serial.println("(RSSI:" +String(rssi) + " / SNR:" + String(snr) + " / FreqErr:" + String(freqError) + ")");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (Config.syslog.active && WiFi.status() == WL_CONNECTED && loraPacket != "") {
|
|
||||||
SYSLOG_Utils::log("Rx", loraPacket, rssi, snr, freqError);
|
|
||||||
}
|
|
||||||
return loraPacket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#ifndef LORA_UTILS_H_
|
|
||||||
#define LORA_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace LoRa_Utils {
|
|
||||||
|
|
||||||
void setup();
|
|
||||||
void sendNewPacket(const String &typeOfMessage, const String &newPacket);
|
|
||||||
String generatePacket(String aprsisPacket);
|
|
||||||
String packetSanitization(String packet);
|
|
||||||
String receivePacket();
|
|
||||||
void changeFreqTx();
|
|
||||||
void changeFreqRx();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -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 && 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 && Config.callsign != "NOCALL-10") timeClient.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFormatedTime() {
|
||||||
|
if (!Config.digi.ecoMode) return timeClient.getFormattedTime();
|
||||||
|
return "DigiEcoMode Active";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "ota_utils.h"
|
#include "ota_utils.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
extern uint32_t lastScreenOn;
|
extern uint32_t lastScreenOn;
|
||||||
extern bool isUpdatingOTA;
|
extern bool isUpdatingOTA;
|
||||||
@@ -29,32 +30,32 @@ namespace OTA_Utils {
|
|||||||
|
|
||||||
void onOTAStart() {
|
void onOTAStart() {
|
||||||
Serial.println("OTA update started!");
|
Serial.println("OTA update started!");
|
||||||
display_toggle(true);
|
displayToggle(true);
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
show_display("", "", "", " OTA update started!", "", "", "", 1000);
|
displayShow("", "", "", " OTA update started!", "", "", "", 1000);
|
||||||
isUpdatingOTA = true;
|
isUpdatingOTA = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onOTAProgress(size_t current, size_t final) {
|
void onOTAProgress(size_t current, size_t final) {
|
||||||
if (millis() - ota_progress_millis > 1000) {
|
if (millis() - ota_progress_millis > 1000) {
|
||||||
display_toggle(true);
|
displayToggle(true);
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
ota_progress_millis = millis();
|
ota_progress_millis = millis();
|
||||||
Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final);
|
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) {
|
void onOTAEnd(bool success) {
|
||||||
display_toggle(true);
|
displayToggle(true);
|
||||||
lastScreenOn = millis();
|
lastScreenOn = millis();
|
||||||
if (success) {
|
|
||||||
Serial.println("OTA update finished successfully!");
|
String statusMessage = success ? "OTA update success!" : "OTA update fail!";
|
||||||
show_display("", "", " OTA update success!", "", " Rebooting ...", "", "", 4000);
|
String rebootMessage = success ? "Rebooting ..." : "";
|
||||||
} else {
|
|
||||||
Serial.println("There was an error during OTA update!");
|
Serial.println(success ? "OTA update finished successfully!" : "There was an error during OTA update!");
|
||||||
show_display("", "", " OTA update fail!", "", "", "", "", 4000);
|
displayShow("", "", statusMessage, "", rebootMessage, "", "", 4000);
|
||||||
}
|
|
||||||
isUpdatingOTA = false;
|
isUpdatingOTA = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
#ifndef PINS_CONFIG_H_
|
|
||||||
#define PINS_CONFIG_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
#undef OLED_SDA
|
|
||||||
#undef OLED_SCL
|
|
||||||
#undef OLED_RST
|
|
||||||
|
|
||||||
#if defined(HELTEC_V3) || defined(ESP32_DIY_1W_LoRa) || defined(TTGO_T_Beam_V1_0_SX1268) || defined(TTGO_T_Beam_V1_2_SX1262)
|
|
||||||
#define HAS_SX126X
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(ESP32_DIY_LoRa) || defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_2)
|
|
||||||
#define HAS_SX127X
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TTGO_T_Beam_V1_0) || defined(TTGO_T_Beam_V1_0_SX1268)
|
|
||||||
#define HAS_AXP192
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(TTGO_T_Beam_V1_2) || defined(TTGO_T_Beam_V1_2_SX1262)
|
|
||||||
#define HAS_AXP2101
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// LORA MODULES
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2) || defined(ESP32_DIY_LoRa)
|
|
||||||
#undef LORA_RST
|
|
||||||
#define LORA_SCK 5 // GPIO5 - SX1276 SCK
|
|
||||||
#define LORA_MISO 19 // GPIO19 - SX1276 MISO
|
|
||||||
#define LORA_MOSI 27 // GPIO27 - SX1276 MOSI
|
|
||||||
#define LORA_CS 18 // GPIO18 - SX1276 CS ---> NSS
|
|
||||||
#define LORA_RST 14 // GPIO14 - SX1276 RST
|
|
||||||
#define LORA_IRQ 26 // GPIO26 - SX1276 IRQ ---->DIO0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HELTEC_V3
|
|
||||||
#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
|
|
||||||
|
|
||||||
#ifdef ESP32_DIY_1W_LoRa // Ebyte E22 400M30S / SX1268
|
|
||||||
#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
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
#define OLED_SDA 21
|
|
||||||
#define OLED_SCL 22
|
|
||||||
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HELTEC_V2
|
|
||||||
#define OLED_SDA 4
|
|
||||||
#define OLED_SCL 15
|
|
||||||
#define OLED_RESET 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HELTEC_V3
|
|
||||||
#define OLED_SDA 17
|
|
||||||
#define OLED_SCL 18
|
|
||||||
#define OLED_RESET 21
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Leds and other stuff
|
|
||||||
#if defined(TTGO_T_LORA32_V2_1) || defined(HELTEC_V2)
|
|
||||||
#define internalLedPin 25 // Green Led
|
|
||||||
#define batteryPin 35
|
|
||||||
#endif
|
|
||||||
#ifdef HELTEC_V3
|
|
||||||
#define internalLedPin 35
|
|
||||||
#endif
|
|
||||||
#if defined(ESP32_DIY_LoRa) || defined(ESP32_DIY_1W_LoRa)
|
|
||||||
#define internalLedPin 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
|
|
||||||
@@ -1,18 +1,27 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "battery_utils.h"
|
||||||
|
#include "board_pinout.h"
|
||||||
#include "power_utils.h"
|
#include "power_utils.h"
|
||||||
#include "pins_config.h"
|
|
||||||
|
|
||||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
#define I2C_SDA 21
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
#define I2C_SCL 22
|
#define I2C0_SDA 17
|
||||||
#define IRQ_PIN 35
|
#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
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_AXP192
|
#ifdef HAS_AXP192
|
||||||
XPowersAXP192 PMU;
|
XPowersAXP192 PMU;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_AXP2101
|
#ifdef HAS_AXP2101
|
||||||
XPowersAXP2101 PMU;
|
XPowersAXP2101 PMU;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Configuration Config;
|
extern Configuration Config;
|
||||||
@@ -20,111 +29,248 @@ extern Configuration Config;
|
|||||||
|
|
||||||
namespace POWER_Utils {
|
namespace POWER_Utils {
|
||||||
|
|
||||||
bool BatteryIsConnected = false;
|
double getBatteryVoltage() {
|
||||||
String batteryVoltage = "";
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
String batteryChargeDischargeCurrent = "";
|
return (PMU.getBattVoltage() / 1000.0);
|
||||||
|
#else
|
||||||
|
return 0.0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBatteryConnected() {
|
||||||
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
|
return PMU.isBatteryConnect();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void activateMeasurement() {
|
void activateMeasurement() {
|
||||||
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
#if defined(HAS_AXP192) || defined(HAS_AXP2101)
|
||||||
PMU.disableTSPinMeasure();
|
PMU.disableTSPinMeasure();
|
||||||
PMU.enableBattDetection();
|
PMU.enableBattDetection();
|
||||||
PMU.enableVbusVoltageMeasure();
|
PMU.enableVbusVoltageMeasure();
|
||||||
PMU.enableBattVoltageMeasure();
|
PMU.enableBattVoltageMeasure();
|
||||||
PMU.enableSystemVoltageMeasure();
|
PMU.enableSystemVoltageMeasure();
|
||||||
#endif
|
#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() {
|
void activateLoRa() {
|
||||||
#ifdef HAS_AXP192
|
#ifdef HAS_AXP192
|
||||||
PMU.setLDO2Voltage(3300);
|
PMU.setLDO2Voltage(3300);
|
||||||
PMU.enableLDO2();
|
PMU.enableLDO2();
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_AXP2101
|
#ifdef HAS_AXP2101
|
||||||
PMU.setALDO2Voltage(3300);
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
PMU.enableALDO2();
|
PMU.setALDO3Voltage(3300);
|
||||||
|
PMU.enableALDO3();
|
||||||
|
#else
|
||||||
|
PMU.setALDO2Voltage(3300);
|
||||||
|
PMU.enableALDO2();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void deactivateLoRa() {
|
void deactivateLoRa() {
|
||||||
#ifdef HAS_AXP192
|
#ifdef HAS_AXP192
|
||||||
PMU.disableLDO2();
|
PMU.disableLDO2();
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_AXP2101
|
#ifdef HAS_AXP2101
|
||||||
PMU.disableALDO2();
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
|
PMU.disableALDO3();
|
||||||
|
#else
|
||||||
|
PMU.disableALDO2();
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool begin(TwoWire &port) {
|
bool begin(TwoWire &port) {
|
||||||
#if defined(HAS_AXP192)
|
#if defined(HAS_AXP192)
|
||||||
bool result = PMU.begin(Wire, AXP192_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
|
bool result = PMU.begin(Wire, AXP192_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
|
||||||
if (result) {
|
if (result) {
|
||||||
PMU.disableDC2();
|
PMU.disableDC2();
|
||||||
PMU.disableLDO2();
|
PMU.disableLDO2();
|
||||||
PMU.disableLDO3();
|
PMU.disableLDO3();
|
||||||
PMU.setDC1Voltage(3300);
|
PMU.setDC1Voltage(3300);
|
||||||
PMU.enableDC1();
|
PMU.enableDC1();
|
||||||
PMU.setProtectedChannel(XPOWERS_DCDC3);
|
PMU.setProtectedChannel(XPOWERS_DCDC3);
|
||||||
PMU.disableIRQ(XPOWERS_AXP192_ALL_IRQ);
|
PMU.disableIRQ(XPOWERS_AXP192_ALL_IRQ);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
#elif defined(HAS_AXP2101)
|
#elif defined(HAS_AXP2101)
|
||||||
bool result = PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
if (result) {
|
bool result = PMU.begin(Wire1, AXP2101_SLAVE_ADDRESS, I2C1_SDA, I2C1_SCL);
|
||||||
PMU.disableDC2();
|
#else
|
||||||
PMU.disableDC3();
|
bool result = PMU.begin(Wire, AXP2101_SLAVE_ADDRESS, I2C_SDA, I2C_SCL);
|
||||||
PMU.disableDC4();
|
#endif
|
||||||
PMU.disableDC5();
|
if (result) {
|
||||||
PMU.disableALDO1();
|
PMU.disableDC2();
|
||||||
PMU.disableALDO4();
|
PMU.disableDC3();
|
||||||
PMU.disableBLDO1();
|
PMU.disableDC4();
|
||||||
PMU.disableBLDO2();
|
PMU.disableDC5();
|
||||||
PMU.disableDLDO1();
|
#ifndef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
PMU.disableDLDO2();
|
PMU.disableALDO1();
|
||||||
PMU.setDC1Voltage(3300);
|
PMU.disableALDO4();
|
||||||
PMU.enableDC1();
|
#endif
|
||||||
PMU.setButtonBatteryChargeVoltage(3300);
|
PMU.disableBLDO1();
|
||||||
PMU.enableButtonBatteryCharge();
|
PMU.disableBLDO2();
|
||||||
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
PMU.disableDLDO1();
|
||||||
}
|
PMU.disableDLDO2();
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Wire.end();
|
|
||||||
#ifdef HAS_AXP192
|
#ifdef HAS_AXP192
|
||||||
Wire.begin(SDA, SCL);
|
Wire.begin(SDA, SCL);
|
||||||
if (begin(Wire)) {
|
if (begin(Wire)) {
|
||||||
Serial.println("AXP192 init done!");
|
Serial.println("AXP192 init done!");
|
||||||
} else {
|
} else {
|
||||||
Serial.println("AXP192 init failed!");
|
Serial.println("AXP192 init failed!");
|
||||||
}
|
}
|
||||||
activateLoRa();
|
activateLoRa();
|
||||||
activateMeasurement();
|
activateMeasurement();
|
||||||
PMU.setChargerTerminationCurr(XPOWERS_AXP192_CHG_ITERM_LESS_10_PERCENT);
|
PMU.setChargerTerminationCurr(XPOWERS_AXP192_CHG_ITERM_LESS_10_PERCENT);
|
||||||
PMU.setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
PMU.setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||||
PMU.setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_780MA);
|
PMU.setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_780MA);
|
||||||
PMU.setSysPowerDownVoltage(2600);
|
PMU.setSysPowerDownVoltage(2600);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_AXP2101
|
#ifdef HAS_AXP2101
|
||||||
Wire.begin(SDA, SCL);
|
bool beginStatus = false;
|
||||||
if (begin(Wire)) {
|
#ifdef TTGO_T_Beam_S3_SUPREME_V3
|
||||||
Serial.println("AXP2101 init done!");
|
Wire1.begin(I2C1_SDA, I2C1_SCL);
|
||||||
} else {
|
Wire.begin(I2C0_SDA, I2C0_SCL);
|
||||||
Serial.println("AXP2101 init failed!");
|
if (begin(Wire1)) beginStatus = true;
|
||||||
}
|
#else
|
||||||
activateLoRa();
|
Wire.begin(SDA, SCL);
|
||||||
activateMeasurement();
|
if (begin(Wire)) beginStatus = true;
|
||||||
PMU.setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_200MA);
|
#endif
|
||||||
PMU.setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_25MA);
|
if (beginStatus) {
|
||||||
PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
|
Serial.println("AXP2101 init done!");
|
||||||
PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_800MA);
|
} else {
|
||||||
PMU.setSysPowerDownVoltage(2600);
|
Serial.println("AXP2101 init failed!");
|
||||||
|
}
|
||||||
|
activateLoRa();
|
||||||
|
activateMeasurement();
|
||||||
|
PMU.setPrechargeCurr(XPOWERS_AXP2101_PRECHARGE_200MA);
|
||||||
|
PMU.setChargerTerminationCurr(XPOWERS_AXP2101_CHG_ITERM_25MA);
|
||||||
|
PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
|
||||||
|
PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_800MA);
|
||||||
|
PMU.setSysPowerDownVoltage(2600);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BATTERY_PIN
|
||||||
|
pinMode(BATTERY_PIN, INPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INTERNAL_LED_PIN
|
||||||
|
pinMode(INTERNAL_LED_PIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Config.battery.sendExternalVoltage || Config.battery.monitorExternalVoltage) {
|
||||||
|
pinMode(Config.battery.externalVoltagePin, INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VEXT_CTRL
|
||||||
|
pinMode(VEXT_CTRL,OUTPUT); // GPS + TFT on HELTEC Wireless_Tracker and only for Oled in HELTEC V3
|
||||||
|
#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) activateGPS();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ADC_CTRL
|
||||||
|
pinMode(ADC_CTRL, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HELTEC_WIRELESS_TRACKER)
|
||||||
|
Wire.begin(BOARD_I2C_SDA, BOARD_I2C_SCL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#ifndef POWER_UTILS_H_
|
|
||||||
#define POWER_UTILS_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "XPowersLib.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace POWER_Utils {
|
|
||||||
|
|
||||||
void activateMeasurement();
|
|
||||||
void activateLoRa();
|
|
||||||
void deactivateLoRa();
|
|
||||||
bool begin(TwoWire &port);
|
|
||||||
void setup();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,48 +1,141 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "battery_utils.h"
|
||||||
|
#include "station_utils.h"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
|
#include "lora_utils.h"
|
||||||
|
|
||||||
extern Configuration Config;
|
|
||||||
extern std::vector<String> lastHeardStation;
|
extern Configuration Config;
|
||||||
extern std::vector<String> lastHeardStation_temp;
|
extern std::vector<LastHeardStation> lastHeardStations;
|
||||||
extern String versionDate;
|
extern String versionDate;
|
||||||
|
extern int rssi;
|
||||||
|
extern float snr;
|
||||||
|
extern int freqError;
|
||||||
|
extern bool shouldSleepLowVoltage;
|
||||||
|
extern bool saveNewDigiEcoModeConfig;
|
||||||
|
|
||||||
|
|
||||||
namespace QUERY_Utils {
|
namespace QUERY_Utils {
|
||||||
|
|
||||||
String process(String query, String station, String queryOrigin) {
|
String process(const String& query, const String& station, bool queryFromAPRSIS, bool thirdParty) {
|
||||||
String answer;
|
String answer;
|
||||||
if (query=="?APRS?" || query=="?aprs?" || query=="?Aprs?" || query=="H" || query=="h" || query=="HELP" || query=="Help" || query=="help" || query=="?") {
|
String queryQuestion = query;
|
||||||
answer = "?APRSV ?APRSP ?APRSL ?APRSH ?WHERE callsign";
|
queryQuestion.toUpperCase();
|
||||||
} else if (query=="?APRSV" || query=="?aprsv" || query=="?Aprsv") {
|
if (queryQuestion == "?APRS?" || queryQuestion == "H" || queryQuestion == "HELP" || queryQuestion=="?") {
|
||||||
answer = "CA2RXU_LoRa_iGate 1.3 v" + versionDate;
|
answer.concat("?APRSV ?APRSP ?APRSL ?APRSSSR ?EM=? ?TX=? "); // ?APRSH ?WHERE callsign
|
||||||
} else if (query=="?APRSP" || query=="?aprsp" || query=="?Aprsp") {
|
} else if (queryQuestion == "?APRSV") {
|
||||||
answer = "iGate QTH: " + String(Config.beacon.latitude,2) + " " + String(Config.beacon.longitude,2);
|
answer.concat("CA2RXU_LoRa_iGate 2.3 v");
|
||||||
} else if (query=="?APRSL" || query=="?aprsl" || query=="?Aprsl") {
|
answer.concat(versionDate);
|
||||||
if (lastHeardStation.size() == 0) {
|
} else if (queryQuestion == "?APRSP") {
|
||||||
answer = "No Station Listened in the last " + String(Config.rememberStationTime) + "min.";
|
answer.concat("iGate QTH: ");
|
||||||
|
answer.concat(String(Config.beacon.latitude,3));
|
||||||
|
answer.concat(" ");
|
||||||
|
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 {
|
} else {
|
||||||
for (int i=0; i<lastHeardStation.size(); i++) {
|
for (int i=0; i<lastHeardStations.size(); i++) {
|
||||||
answer += lastHeardStation[i].substring(0,lastHeardStation[i].indexOf(",")) + " ";
|
answer += lastHeardStations[i].station + " ";
|
||||||
}
|
}
|
||||||
answer.trim();
|
answer.trim();
|
||||||
}
|
}
|
||||||
} else if (query.indexOf("?APRSH") == 0 || query.indexOf("?aprsh") == 0 || query.indexOf("?Aprsh") == 0) {
|
} else if (queryQuestion == "?APRSSR") {
|
||||||
|
char signalData[35];
|
||||||
|
snprintf(signalData, sizeof(signalData), " %ddBm / %.2fdB / %dHz", rssi, snr, freqError);
|
||||||
|
answer.concat(signalData);
|
||||||
|
} /*else if (queryQuestion.indexOf("?APRSH") == 0) {
|
||||||
// sacar callsign despues de ?APRSH
|
// sacar callsign despues de ?APRSH
|
||||||
Serial.println("escuchaste a X estacion? en las ultimas 24 o 8 horas?");
|
Serial.println("escuchaste a X estacion? en las ultimas 24 o 8 horas?");
|
||||||
answer = "APRSH on development 73!";
|
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
|
// agregar callsign para completar donde esta X callsign --> posicion
|
||||||
Serial.println("estaciones escuchadas directo (ultimos 30 min)");
|
Serial.println("estaciones escuchadas directo (ultimos 30 min)");
|
||||||
answer = "?WHERE on development 73!";
|
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) { // Exit Digipeater EcoMode
|
||||||
|
answer = "DigiEcoMode:OFF";
|
||||||
|
Config.digi.ecoMode = false;
|
||||||
|
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) { // Start Digipeater EcoMode
|
||||||
|
answer = "DigiEcoMode:ON";
|
||||||
|
Config.digi.ecoMode = true;
|
||||||
|
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
|
||||||
|
answer = (Config.digi.ecoMode) ? "DigiEcoMode:ON" : "DigiEcoMode:OFF";
|
||||||
|
} 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(int i = station.length(); i < 9; i++) {
|
|
||||||
station += ' ';
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (queryOrigin == "APRSIS") {
|
queryAnswer += "::";
|
||||||
return Config.callsign + ">APLRG1,TCPIP,qAC::" + station + ":" + answer;// + "\n";
|
|
||||||
} else { //} if (queryOrigin == "LoRa") {
|
String processedStation = station;
|
||||||
return Config.callsign + ">APLRG1,RFONLY,WIDE1-1::" + station + ":" + answer;
|
for (int i = station.length(); i < 9; i++) {
|
||||||
|
processedStation += ' ';
|
||||||
}
|
}
|
||||||
|
queryAnswer += processedStation;
|
||||||
|
queryAnswer += ":";
|
||||||
|
queryAnswer += answer;
|
||||||
|
|
||||||
|
queryAnswer += " *";
|
||||||
|
queryAnswer += char(random(97, 123));
|
||||||
|
queryAnswer += char(random(97, 123));
|
||||||
|
queryAnswer += "*";
|
||||||
|
return queryAnswer;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||