kopia lustrzana https://github.com/dl9rdz/rdz_ttgo_sonde
Squashed commit of the following:
commitmasterfcaf88779d
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sun Jan 7 12:22:16 2024 +0000 (read partition table; preparation for future file system upload script) commit9c7491d389
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sat Jan 6 23:51:44 2024 +0000 better license info on external libraries commit12ede0e81d
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Mon Dec 18 19:12:36 2023 +0100 esp32 version update commit1687117bec
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Dec 12 19:36:47 2023 +0000 tentative fix of M20 misclassification as M10 (untested) commitff5aec544e
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Dec 12 19:27:23 2023 +0000 tentative fix of M20 misclassification as M10 (untested) commit2b88e072ac
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sun Dec 10 16:11:51 2023 +0000 reduce image size with platformio builds, make it (almost) same as for Arduino builds commit8ee071de35
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sun Dec 3 22:45:44 2023 +0000 T-Beam 1.2: charge battery fix commit681f436767
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sun Dec 3 16:00:13 2023 +0000 newer library versions commit6551fa0b5d
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Fri Nov 10 09:43:02 2023 +0000 chasemapper: id format with type, as in auto_rx commite5c2e2db77
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Aug 29 20:15:53 2023 +0000 more explanation in About tabw commitaec4d39867
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Aug 29 01:00:53 2023 +0000 fix travis build / wget issue with github commitd7026abb7b
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Aug 29 00:22:48 2023 +0000 fix bug in eph config editor commit6c98891b63
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Mon Aug 28 12:35:06 2023 +0000 AXP2101: add missing irq handler commitc1231a11d4
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Mon Aug 28 12:02:36 2023 +0000 bugfix (APX2101 related) commit86263a7ad1
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Mon Aug 28 10:13:39 2023 +0000 fix commit35156948cb
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Mon Aug 28 10:07:09 2023 +0000 yet another fix for ftp eph commit3ddbebf2fc
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sat Aug 26 23:33:33 2023 +0000 untested axp2101 support commit60e97d917b
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sat Aug 26 17:19:38 2023 +0000 pmu reorg, preparing for axp2101 commit082b6ccdf5
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Tue Aug 22 22:28:37 2023 +0000 fix posInfo bug; aprs timeout convert seconds to ms commitdeec0d362f
Author: Hansi, dl9rdz <dl9rdz@darc.de> Date: Sun Jul 9 12:10:53 2023 +0200 (sync with master) some code reorganization, preliminary SD card code (not active) APRS timeout added
rodzic
6cf330b143
commit
5ce1d36b97
20
.travis.yml
20
.travis.yml
|
@ -1,3 +1,9 @@
|
||||||
|
# safelist
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- devel
|
||||||
|
|
||||||
language: c
|
language: c
|
||||||
dist: focal
|
dist: focal
|
||||||
os: linux
|
os: linux
|
||||||
|
@ -17,20 +23,20 @@ before_install:
|
||||||
- tar xf arduino-1.8.16-linux64.tar.xz
|
- tar xf arduino-1.8.16-linux64.tar.xz
|
||||||
- sudo mv arduino-1.8.16 /usr/local/share/arduino
|
- sudo mv arduino-1.8.16 /usr/local/share/arduino
|
||||||
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
|
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
|
||||||
- wget https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
|
- wget --secure-protocol=TLSv1_2 https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
|
||||||
- unzip master.zip
|
- unzip master.zip
|
||||||
- rm master.zip
|
- rm master.zip
|
||||||
- sudo mv ESPAsyncWebServer-master /usr/local/share/arduino/libraries/ESPAsyncWebServer
|
- sudo mv ESPAsyncWebServer-master /usr/local/share/arduino/libraries/ESPAsyncWebServer
|
||||||
- wget https://github.com/me-no-dev/AsyncTCP/archive/master.zip
|
- wget --secure-protocol=TLSv1_2 https://github.com/me-no-dev/AsyncTCP/archive/master.zip
|
||||||
- unzip master.zip
|
- unzip master.zip
|
||||||
- rm master.zip
|
- rm master.zip
|
||||||
- sudo mv AsyncTCP-master /usr/local/share/arduino/libraries/AsyncTCP
|
- sudo mv AsyncTCP-master /usr/local/share/arduino/libraries/AsyncTCP
|
||||||
- wget https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/download/1.0/ESP32FS-1.0.zip
|
- wget --secure-protocol=TLSv1_2 https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/download/1.0/ESP32FS-1.0.zip
|
||||||
- wget https://github.com/lewisxhe/AXP202X_Library/archive/refs/tags/V1.1.3.zip
|
- wget --secure-protocol=TLSv1_2 https://github.com/lewisxhe/AXP202X_Library/archive/refs/tags/V1.1.3.zip
|
||||||
- unzip V1.1.3.zip
|
- unzip V1.1.3.zip
|
||||||
- sudo mv AXP202X_Library-1.1.3 /usr/local/share/arduino/libraries/
|
- sudo mv AXP202X_Library-1.1.3 /usr/local/share/arduino/libraries/
|
||||||
|
|
||||||
- wget https://github.com/dx168b/async-mqtt-client/archive/master.zip
|
- wget --secure-protocol=TLSv1_2 https://github.com/dx168b/async-mqtt-client/archive/master.zip
|
||||||
- unzip master.zip
|
- unzip master.zip
|
||||||
- rm master.zip
|
- rm master.zip
|
||||||
- sudo mv async-mqtt-client-master /usr/local/share/arduino/libraries/
|
- sudo mv async-mqtt-client-master /usr/local/share/arduino/libraries/
|
||||||
|
@ -53,9 +59,9 @@ install:
|
||||||
- arduino --pref "build.path=$PWD/build" --save-prefs
|
- arduino --pref "build.path=$PWD/build" --save-prefs
|
||||||
- arduino --install-boards esp32:esp32:1.0.6 --save-prefs
|
- arduino --install-boards esp32:esp32:1.0.6 --save-prefs
|
||||||
- ln -s $PWD/libraries/SondeLib /usr/local/share/arduino/libraries/SondeLib
|
- ln -s $PWD/libraries/SondeLib /usr/local/share/arduino/libraries/SondeLib
|
||||||
- arduino --install-library "U8g2:2.29.11"
|
- arduino --install-library "U8g2:2.34.22"
|
||||||
- arduino --install-library "MicroNMEA"
|
- arduino --install-library "MicroNMEA"
|
||||||
- arduino --install-library "GFX Library for Arduino:1.1.5"
|
- arduino --install-library "GFX Library for Arduino:1.2.9"
|
||||||
script:
|
script:
|
||||||
- arduino --board esp32:esp32:t-beam --verify $PWD/RX_FSK/RX_FSK.ino
|
- arduino --board esp32:esp32:t-beam --verify $PWD/RX_FSK/RX_FSK.ino
|
||||||
- ESPPATH=`arduino --get-pref runtime.tools.xtensa-esp32-elf-gcc.path`
|
- ESPPATH=`arduino --get-pref runtime.tools.xtensa-esp32-elf-gcc.path`
|
||||||
|
|
|
@ -1,11 +1,51 @@
|
||||||
GPL License Exceptions:
|
GPL License Exceptions
|
||||||
|
|
||||||
- The SX1278FSK library is based on
|
Code in the repository:
|
||||||
|
|
||||||
|
- The SX1278FSK library (src/SX1278FSK.cpp) is based on
|
||||||
https://github.com/pdelmo/lora_shield_arduino.git
|
https://github.com/pdelmo/lora_shield_arduino.git
|
||||||
and licensed under
|
and licensed under
|
||||||
GNU Lesser General Public License, version 2.1 (SPDX short identifier: LGPL-2.1)
|
GNU Lesser General Public License, version 2.1 (SPDX short identifier: LGPL-2.1)
|
||||||
|
|
||||||
- Leaflet sidebar v2 plugin is (c) 2013 Tobias Bieniek based on
|
- General purpose Reed-Solomon decoder for 8-bit symbols or less
|
||||||
https://github.com/Turbo87/sidebar-v2/
|
Copyright 2003 Phil Karn, KA9Q
|
||||||
and licensed under
|
May be used under the terms of the GNU Lesser General Public License (LGPL) - lgpl-2.1.txt
|
||||||
MIT License
|
|
||||||
|
- some of the decoder code is more or less loosly inspired by
|
||||||
|
* oe5dxl aprs toolchain (http://oe5dxl.hamspirit.at:8025), licensed under GNU GPL (gpl-3.0.txt)
|
||||||
|
* Zilogs RS decoder (https://github.com/rs1729/RS), licensed under GNU GPL (gpl-3.0.txt)
|
||||||
|
|
||||||
|
- Fonts in src/fonts (FreeMono*, FreeSans*, Picopixel) taken from Adafruit-GFX-Library
|
||||||
|
licensed under BSD License
|
||||||
|
Font src/fonts/Terminal11x16.h taken from https://github.com/Nkawu/TFT_22_ILI9225/
|
||||||
|
licensed under GPL-3.0
|
||||||
|
|
||||||
|
External libraries used by the project:
|
||||||
|
|
||||||
|
- Espressif 32: development platform for PlatformIO
|
||||||
|
https://github.com/platformio/platform-espressif32
|
||||||
|
licensed under Apache-2.0 licsense - apache.txt
|
||||||
|
|
||||||
|
- U8glib library for monochrome displays, version 2
|
||||||
|
https://github.com/olikraus/u8g2
|
||||||
|
licensed under the new-bsd license (two-clause bsd license) - LICENSE-u8g2.txt
|
||||||
|
|
||||||
|
- MicroNMEA - A compact Arduino library to parse NMEA sentences
|
||||||
|
https://github.com/stevemarple/MicroNMEA
|
||||||
|
licsensed under LGPL-2.1 license - lgpl-2.1.txt
|
||||||
|
|
||||||
|
- ESPAsyncWebServer
|
||||||
|
see https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/src/ESPAsyncWebServer.h#L7-L19
|
||||||
|
licsensed under LGPL-2.1 license - lgpl-2.1.txt
|
||||||
|
|
||||||
|
- Arduino GFX developing for various color displays
|
||||||
|
https://github.com/moononournation/Arduino_GFX
|
||||||
|
licensed under BSD License - LICENSE-Arduino_GFX.txt
|
||||||
|
|
||||||
|
- asynchronous MQTT client implementation
|
||||||
|
https://github.com/dx168b/async-mqtt-client
|
||||||
|
licensed under MIT license - LICENSE-mqtt.txt
|
||||||
|
|
||||||
|
- Time library for Arduino
|
||||||
|
https://github.com/PaulStoffregen/Time
|
||||||
|
licensed under LGPL-2.1 licsense - lgpl-2.1txt
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
Software License Agreement (BSD License)
|
||||||
|
|
||||||
|
Copyright (c) 2012 Adafruit Industries. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
- Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Marvin Roger
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
The U8g2lib code (https://github.com/olikraus/u8g2) is licensed under the terms of
|
||||||
|
the new-bsd license (two-clause bsd license).
|
||||||
|
See also: http://www.opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
Fonts are licensed under different conditions.
|
||||||
|
See
|
||||||
|
https://github.com/olikraus/u8g2/wiki/fntgrp
|
||||||
|
for detailed information on the licensing conditions for each font.
|
||||||
|
|
||||||
|
The example code in sys/raspi_gpio/hal will use the bcm2835 lib from Mike McCauley
|
||||||
|
which is licensed under GPL V3: http://www.airspayce.com/mikem/bcm2835/
|
||||||
|
|
||||||
|
============ X11 Fonts COUR, HELV, NCEN, TIM, SYMB ============
|
||||||
|
|
||||||
|
For fonts derived from the following files, the license below applies.
|
||||||
|
COURB08.BDF COURB10.BDF COURB12.BDF COURB14.BDF COURB18.BDF
|
||||||
|
COURB24.BDF COURR08.BDF COURR10.BDF COURR12.BDF COURR14.BDF
|
||||||
|
COURR18.BDF COURR24.BDF HELVB08.BDF HELVB10.BDF HELVB12.BDF HELVB14.BDF
|
||||||
|
HELVB18.BDF HELVB24.BDF HELVR08.BDF HELVR10.BDF HELVR12.BDF HELVR14.BDF
|
||||||
|
HELVR18.BDF HELVR24.BDF NCENB08.BDF NCENB10.BDF NCENB12.BDF
|
||||||
|
NCENB14.BDF NCENB18.BDF NCENB24.BDF NCENR08.BDF NCENR10.BDF
|
||||||
|
NCENR12.BDF NCENR14.BDF NCENR18.BDF NCENR24.BDF SYMB08.BDF SYMB10.BDF
|
||||||
|
SYMB12.BDF SYMB14.BDF SYMB18.BDF SYMB24.BDF TIMB08.BDF TIMB10.BDF
|
||||||
|
TIMB12.BDF TIMB14.BDF TIMB18.BDF TIMB24.BDF TIMR08.BDF TIMR10.BDF
|
||||||
|
TIMR12.BDF TIMR14.BDF TIMR18.BDF TIMR24.BDF
|
||||||
|
|
||||||
|
Copyright 1984-1989, 1994 Adobe Systems Incorporated.
|
||||||
|
Copyright 1988, 1994 Digital Equipment Corporation.
|
||||||
|
|
||||||
|
Adobe is a trademark of Adobe Systems Incorporated which may be
|
||||||
|
registered in certain jurisdictions.
|
||||||
|
Permission to use these trademarks is hereby granted only in
|
||||||
|
association with the images described in this file.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, distribute and sell this software
|
||||||
|
and its documentation for any purpose and without fee is hereby
|
||||||
|
granted, provided that the above copyright notices appear in all
|
||||||
|
copies and that both those copyright notices and this permission
|
||||||
|
notice appear in supporting documentation, and that the names of
|
||||||
|
Adobe Systems and Digital Equipment Corporation not be used in
|
||||||
|
advertising or publicity pertaining to distribution of the software
|
||||||
|
without specific, written prior permission. Adobe Systems and
|
||||||
|
Digital Equipment Corporation make no representations about the
|
||||||
|
suitability of this software for any purpose. It is provided "as
|
||||||
|
is" without express or implied warranty.
|
||||||
|
|
||||||
|
|
||||||
|
============ BSD License for U8g2lib Code ============
|
||||||
|
|
||||||
|
Universal 8bit Graphics Library (https://github.com/olikraus/u8g2)
|
||||||
|
|
||||||
|
Copyright (c) 2016, olikraus@gmail.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this list
|
||||||
|
of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||||
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
Plik diff jest za duży
Load Diff
|
@ -42,6 +42,7 @@ var cfgs = [
|
||||||
[ "axudp.port", "AXUDP port"],
|
[ "axudp.port", "AXUDP port"],
|
||||||
[ "axudp.highrate", "Rate limit"],
|
[ "axudp.highrate", "Rate limit"],
|
||||||
[ "tcp.active", "APRS TCP active"],
|
[ "tcp.active", "APRS TCP active"],
|
||||||
|
[ "tcp.timeout", "APRS TCP timeout [s] (0=off, 25=on)"],
|
||||||
[ "tcp.host", "APRS TCP host"],
|
[ "tcp.host", "APRS TCP host"],
|
||||||
[ "tcp.port", "APRS TCP port"],
|
[ "tcp.port", "APRS TCP port"],
|
||||||
[ "tcp.highrate", "Rate limit"],
|
[ "tcp.highrate", "Rate limit"],
|
||||||
|
|
|
@ -15,6 +15,7 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||||
fetch('live.json')
|
fetch('live.json')
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
if (data.gps===undefined) { data.gps={} };
|
||||||
console.log(data.gps.lat, data.gps.lon, data.sonde.ser);
|
console.log(data.gps.lat, data.gps.lon, data.sonde.ser);
|
||||||
if( (data.sonde.ser||'')=='' && !(data.gps.lat===undefined) ) {
|
if( (data.sonde.ser||'')=='' && !(data.gps.lat===undefined) ) {
|
||||||
urlarg = maps[maptype][2](data.gps.lat, data.gps.lon);
|
urlarg = maps[maptype][2](data.gps.lat, data.gps.lon);
|
||||||
|
|
|
@ -2,12 +2,17 @@
|
||||||
// Configuration flags for including/excluding fuctionality from the compiled binary
|
// Configuration flags for including/excluding fuctionality from the compiled binary
|
||||||
// set flag to 0 for exclude/1 for include
|
// set flag to 0 for exclude/1 for include
|
||||||
|
|
||||||
/* data feed to sondehubv2 */
|
// Selection of data output connectors to be included in firmware
|
||||||
/* needs about 4k4 code, 200b data, 200b stack, 200b heap */
|
// APRS includes AXUDP (e.g. for aprsmap) and APRS-IS (TCP) (e.g. for wettersonde.net, radiosondy.info)
|
||||||
#define FEATURE_SONDEHUB 1
|
#define FEATURE_SONDEHUB 1
|
||||||
|
|
||||||
#define FEATURE_CHASEMAPPER 1
|
#define FEATURE_CHASEMAPPER 1
|
||||||
#define FEATURE_MQTT 1
|
#define FEATURE_MQTT 1
|
||||||
|
#define FEATURE_SDCARD 0
|
||||||
|
#define FEATURE_APRS 1
|
||||||
|
|
||||||
|
|
||||||
|
// Additional optional components
|
||||||
#define FEATURE_RS92 1
|
#define FEATURE_RS92 1
|
||||||
|
|
||||||
/* Most recent version support fonts in a dedicated flash parition "fonts".
|
/* Most recent version support fonts in a dedicated flash parition "fonts".
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef _CHASEMAPPER_H
|
|
||||||
#define _CHASEMAPPER_H
|
|
||||||
|
|
||||||
#include "Sonde.h"
|
|
||||||
//#include <WiFi.h>
|
|
||||||
#include <WiFiUdp.h>
|
|
||||||
#include <time.h>
|
|
||||||
class Chasemapper {
|
|
||||||
public:
|
|
||||||
static int send(WiFiUDP &udb, SondeInfo *si);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,10 +2,10 @@
|
||||||
#include <U8x8lib.h>
|
#include <U8x8lib.h>
|
||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
#include <axp20x.h>
|
|
||||||
#include <MicroNMEA.h>
|
#include <MicroNMEA.h>
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include "Sonde.h"
|
#include "Sonde.h"
|
||||||
|
#include "pmu.h"
|
||||||
|
|
||||||
int readLine(Stream &stream, char *buffer, int maxlen);
|
int readLine(Stream &stream, char *buffer, int maxlen);
|
||||||
|
|
||||||
|
@ -22,8 +22,7 @@ extern const char *version_id;
|
||||||
|
|
||||||
extern Sonde sonde;
|
extern Sonde sonde;
|
||||||
|
|
||||||
extern AXP20X_Class axp;
|
extern PMU *pmu;
|
||||||
extern bool axp192_found;
|
|
||||||
extern SemaphoreHandle_t axpSemaphore;
|
extern SemaphoreHandle_t axpSemaphore;
|
||||||
|
|
||||||
extern xSemaphoreHandle globalLock;
|
extern xSemaphoreHandle globalLock;
|
||||||
|
@ -33,8 +32,6 @@ extern xSemaphoreHandle globalLock;
|
||||||
} while (xSemaphoreTake(globalLock, portMAX_DELAY) != pdPASS)
|
} while (xSemaphoreTake(globalLock, portMAX_DELAY) != pdPASS)
|
||||||
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(globalLock)
|
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(globalLock)
|
||||||
|
|
||||||
struct GpsPos gpsPos;
|
|
||||||
|
|
||||||
//SPIClass spiDisp(HSPI);
|
//SPIClass spiDisp(HSPI);
|
||||||
|
|
||||||
byte myIP_tiles[8*11];
|
byte myIP_tiles[8*11];
|
||||||
|
@ -1670,13 +1667,14 @@ void Display::drawGPS(DispEntry *de) {
|
||||||
void Display::drawBatt(DispEntry *de) {
|
void Display::drawBatt(DispEntry *de) {
|
||||||
float val;
|
float val;
|
||||||
char buf[30];
|
char buf[30];
|
||||||
if (!axp192_found) {
|
if (!pmu) {
|
||||||
if (sonde.config.batt_adc<0) return;
|
if (sonde.config.batt_adc<0) return;
|
||||||
switch (de->extra[0])
|
switch (de->extra[0])
|
||||||
{
|
{
|
||||||
case 'V':
|
case 'V':
|
||||||
val = (float)(analogRead(sonde.config.batt_adc)) / 4095 * 2 * 3.3 * 1.1;
|
val = (float)(analogRead(sonde.config.batt_adc)) / 4095 * 2 * 3.3 * 1.1;
|
||||||
snprintf(buf, 30, "%.2f%s", val, de->extra + 1);
|
snprintf(buf, 30, "%.2f%s", val, de->extra + 1);
|
||||||
|
Serial.printf("Batt: %s", buf);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*buf = 0;
|
*buf = 0;
|
||||||
|
@ -1684,51 +1682,67 @@ void Display::drawBatt(DispEntry *de) {
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
drawString(de, buf);
|
drawString(de, buf);
|
||||||
} else {
|
} else {
|
||||||
|
*buf = 0;
|
||||||
xSemaphoreTake( axpSemaphore, portMAX_DELAY );
|
xSemaphoreTake( axpSemaphore, portMAX_DELAY );
|
||||||
switch(de->extra[0]) {
|
switch(de->extra[0]) {
|
||||||
case 'S':
|
case 'S':
|
||||||
if(!axp.isBatteryConnect()) {
|
if(!pmu->isBatteryConnected()) {
|
||||||
if(axp.isVBUSPlug()) { strcpy(buf, "U"); }
|
if(pmu->isVbusIn()) { strcpy(buf, "U"); }
|
||||||
else { strcpy(buf, "N"); } // no battary
|
else { strcpy(buf, "N"); } // no battary
|
||||||
}
|
}
|
||||||
else if (axp.isChargeing()) { strcpy(buf, "C"); } // charging
|
else if (pmu->isCharging()) { strcpy(buf, "C"); } // charging
|
||||||
else { strcpy(buf, "B"); } // battery, but not charging
|
else { strcpy(buf, "B"); } // battery, but not charging
|
||||||
|
Serial.printf("Battery: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
val = axp.getBattVoltage();
|
val = pmu->getBattVoltage();
|
||||||
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
|
||||||
|
Serial.printf("Vbatt: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'C':
|
}
|
||||||
val = axp.getBattChargeCurrent();
|
if(pmu->type==TYPE_AXP192) {
|
||||||
|
switch(de->extra[0]) {
|
||||||
|
case 'C':
|
||||||
|
val = pmu->getBattChargeCurrent();
|
||||||
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
||||||
|
Serial.printf("Icharge: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
val = axp.getBattDischargeCurrent();
|
val = pmu->getBattDischargeCurrent();
|
||||||
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
||||||
|
Serial.printf("Idischarge: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
if(sonde.config.type == TYPE_M5_CORE2) {
|
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||||
val = axp.getAcinVoltage();
|
val = pmu->getAcinVoltage();
|
||||||
} else {
|
} else {
|
||||||
val = axp.getVbusVoltage();
|
val = pmu->getVbusVoltage();
|
||||||
}
|
}
|
||||||
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
|
||||||
|
Serial.printf("Vbus: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
if(sonde.config.type == TYPE_M5_CORE2) {
|
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||||
val = axp.getAcinCurrent();
|
val = pmu->getAcinCurrent();
|
||||||
} else {
|
} else {
|
||||||
val = axp.getVbusCurrent();
|
val = pmu->getVbusCurrent();
|
||||||
}
|
}
|
||||||
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
||||||
|
Serial.printf("Ibus: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
val = axp.getTemp(); // fixed in newer versions of libraray: -144.7 no longer needed here!
|
val = pmu->getTemperature();
|
||||||
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
||||||
|
Serial.printf("temp: %s\n", buf);
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
*buf=0;
|
} else if (pmu->type == TYPE_AXP2101) {
|
||||||
}
|
*buf = 0;
|
||||||
|
if(de->extra[0]=='T') {
|
||||||
|
val = pmu->getTemperature();
|
||||||
|
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
xSemaphoreGive( axpSemaphore );
|
xSemaphoreGive( axpSemaphore );
|
||||||
rdis->setFont(de->fmt);
|
rdis->setFont(de->fmt);
|
||||||
drawString(de, buf);
|
drawString(de, buf);
|
||||||
|
|
|
@ -9,18 +9,7 @@
|
||||||
#include <U8x8lib.h>
|
#include <U8x8lib.h>
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
struct GpsPos {
|
#include "posinfo.h"
|
||||||
double lat;
|
|
||||||
double lon;
|
|
||||||
int alt;
|
|
||||||
int course;
|
|
||||||
float speed;
|
|
||||||
int sat;
|
|
||||||
int accuracy;
|
|
||||||
int hdop;
|
|
||||||
int valid;
|
|
||||||
};
|
|
||||||
extern struct GpsPos gpsPos;
|
|
||||||
|
|
||||||
#define WIDTH_AUTO 9999
|
#define WIDTH_AUTO 9999
|
||||||
struct DispEntry {
|
struct DispEntry {
|
||||||
|
|
|
@ -304,6 +304,9 @@ int M10M20::decodeframeM10(uint8_t *data) {
|
||||||
Serial.println("Decoding...");
|
Serial.println("Decoding...");
|
||||||
//SondeInfo *si = sonde.si();
|
//SondeInfo *si = sonde.si();
|
||||||
SondeData *si = &(sonde.si()->d);
|
SondeData *si = &(sonde.si()->d);
|
||||||
|
// Set type info to M10
|
||||||
|
memcpy(si->typestr, "M10 ", 5);
|
||||||
|
si->subtype = 1; // subtype 1: M10
|
||||||
|
|
||||||
// Its a M10
|
// Its a M10
|
||||||
// getid...
|
// getid...
|
||||||
|
@ -441,7 +444,7 @@ void M10M20::processM10data(uint8_t dt)
|
||||||
rxsearching = false;
|
rxsearching = false;
|
||||||
rxbitc = 0;
|
rxbitc = 0;
|
||||||
rxp = 0;
|
rxp = 0;
|
||||||
isM20 = false;
|
//isM20 = false;
|
||||||
headerDetected = 1;
|
headerDetected = 1;
|
||||||
#if 1
|
#if 1
|
||||||
int rssi=sx1278.getRSSI();
|
int rssi=sx1278.getRSSI();
|
||||||
|
@ -463,17 +466,17 @@ void M10M20::processM10data(uint8_t dt)
|
||||||
// 64 9F 20 => M10
|
// 64 9F 20 => M10
|
||||||
// 64 49 0x => M10 (?) -- not used here
|
// 64 49 0x => M10 (?) -- not used here
|
||||||
// 45 20 7x => M20
|
// 45 20 7x => M20
|
||||||
if(rxp==2 && dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
if(rxp==2) {
|
||||||
|
// Update: change type only if valid type information in received data
|
||||||
|
if(dataptr[0]==0x45 && dataptr[1]==0x20) { isM20 = true; }
|
||||||
|
else if(/*dataptr[0]==0x64 &&*/ dataptr[1]==0x9F) { isM20 = false; }
|
||||||
|
}
|
||||||
if(isM20) {
|
if(isM20) {
|
||||||
memcpy(sonde.si()->d.typestr, "M20 ", 5);
|
|
||||||
sonde.si()->d.subtype = 2;
|
|
||||||
if(rxp>=M20_FRAMELEN) {
|
if(rxp>=M20_FRAMELEN) {
|
||||||
rxsearching = true;
|
rxsearching = true;
|
||||||
haveNewFrame = decodeframeM20(dataptr);
|
haveNewFrame = decodeframeM20(dataptr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(sonde.si()->d.typestr, "M10 ", 5);
|
|
||||||
sonde.si()->d.subtype = 1;
|
|
||||||
if(rxp>=M10_FRAMELEN) {
|
if(rxp>=M10_FRAMELEN) {
|
||||||
rxsearching = true;
|
rxsearching = true;
|
||||||
haveNewFrame = decodeframeM10(dataptr);
|
haveNewFrame = decodeframeM10(dataptr);
|
||||||
|
@ -578,6 +581,8 @@ int M10M20::decodeframeM20(uint8_t *data) {
|
||||||
|
|
||||||
Serial.println("Decoding...");
|
Serial.println("Decoding...");
|
||||||
// Its a M20
|
// Its a M20
|
||||||
|
memcpy(si->typestr, "M20 ", 5);
|
||||||
|
si->subtype = 2; // subtype 2: M20
|
||||||
// getid...
|
// getid...
|
||||||
// TODO: Adjust ID calculation and serial number reconstruction
|
// TODO: Adjust ID calculation and serial number reconstruction
|
||||||
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};
|
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_RS92
|
||||||
|
|
||||||
/* RS92 decoder functions */
|
/* RS92 decoder functions */
|
||||||
#include "RS92.h"
|
#include "RS92.h"
|
||||||
|
@ -587,3 +589,4 @@ int RS92::waitRXcomplete() {
|
||||||
|
|
||||||
|
|
||||||
RS92 rs92 = RS92();
|
RS92 rs92 = RS92();
|
||||||
|
#endif
|
||||||
|
|
|
@ -28,6 +28,7 @@ const char *sondeTypeStr[NSondeTypes] = { "DFM ", "RS41", "RS92", "Mxx ", "M10 "
|
||||||
const char *sondeTypeLongStr[NSondeTypes] = { "DFM (all)", "RS41", "RS92", "M10/M20", "M10 ", "M20 ", "MP3-H1" };
|
const char *sondeTypeLongStr[NSondeTypes] = { "DFM (all)", "RS41", "RS92", "M10/M20", "M10 ", "M20 ", "MP3-H1" };
|
||||||
const char sondeTypeChar[NSondeTypes] = { 'D', '4', 'R', 'M', 'M', '2', '3' };
|
const char sondeTypeChar[NSondeTypes] = { 'D', '4', 'R', 'M', 'M', '2', '3' };
|
||||||
const char *manufacturer_string[]={"Graw", "Vaisala", "Vaisala", "Meteomodem", "Meteomodem", "Meteomodem", "Meteo-Radiy"};
|
const char *manufacturer_string[]={"Graw", "Vaisala", "Vaisala", "Meteomodem", "Meteomodem", "Meteomodem", "Meteo-Radiy"};
|
||||||
|
const char *DEFEPH="gssc.esa.int/gnss/data/daily/%1$04d/brdc/brdc%2$03d0.%3$02dn.gz";
|
||||||
|
|
||||||
int fingerprintValue[]={ 17, 31, 64, 4, 55, 48, 23, 128+23, 119, 128+119, -1 };
|
int fingerprintValue[]={ 17, 31, 64, 4, 55, 48, 23, 128+23, 119, 128+119, -1 };
|
||||||
const char *fingerprintText[]={
|
const char *fingerprintText[]={
|
||||||
|
@ -258,7 +259,7 @@ void Sonde::defaultConfig() {
|
||||||
config.tcpfeed.port = 12345;
|
config.tcpfeed.port = 12345;
|
||||||
config.tcpfeed.highrate = 10;
|
config.tcpfeed.highrate = 10;
|
||||||
config.kisstnc.active = 0;
|
config.kisstnc.active = 0;
|
||||||
strcpy(config.ephftp,"igs.bkg.bund.de/IGS/BRDC/");
|
strcpy(config.ephftp,DEFEPH);
|
||||||
|
|
||||||
config.mqtt.active = 0;
|
config.mqtt.active = 0;
|
||||||
strcpy(config.mqtt.id, "rdz_sonde_server");
|
strcpy(config.mqtt.id, "rdz_sonde_server");
|
||||||
|
@ -278,6 +279,8 @@ void Sonde::checkConfig() {
|
||||||
if(config.sondehub.fimaxage>48) config.sondehub.fimaxage = 48;
|
if(config.sondehub.fimaxage>48) config.sondehub.fimaxage = 48;
|
||||||
if(config.sondehub.fimaxdist==0) config.sondehub.fimaxdist = 150;
|
if(config.sondehub.fimaxdist==0) config.sondehub.fimaxdist = 150;
|
||||||
if(config.sondehub.fimaxage==0) config.sondehub.fimaxage = 2;
|
if(config.sondehub.fimaxage==0) config.sondehub.fimaxage = 2;
|
||||||
|
// auto upgrade config to new version with format arguments in string
|
||||||
|
if(!strchr(sonde.config.ephftp,'%')) strcpy(sonde.config.ephftp,DEFEPH);
|
||||||
}
|
}
|
||||||
void Sonde::setConfig(const char *cfg) {
|
void Sonde::setConfig(const char *cfg) {
|
||||||
while(*cfg==' '||*cfg=='\t') cfg++;
|
while(*cfg==' '||*cfg=='\t') cfg++;
|
||||||
|
|
|
@ -191,6 +191,7 @@ struct st_feedinfo {
|
||||||
int lowrate;
|
int lowrate;
|
||||||
int highrate;
|
int highrate;
|
||||||
int lowlimit;
|
int lowlimit;
|
||||||
|
int timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
// maybe extend for external Bluetooth interface?
|
// maybe extend for external Bluetooth interface?
|
||||||
|
@ -281,7 +282,7 @@ typedef struct st_rdzconfig {
|
||||||
struct st_dfmconfig dfm;
|
struct st_dfmconfig dfm;
|
||||||
struct st_m10m20config m10m20;
|
struct st_m10m20config m10m20;
|
||||||
struct st_mp3hconfig mp3h;
|
struct st_mp3hconfig mp3h;
|
||||||
char ephftp[40];
|
char ephftp[80];
|
||||||
// data feed configuration
|
// data feed configuration
|
||||||
// for now, one feed for each type is enough, but might get extended to more?
|
// for now, one feed for each type is enough, but might get extended to more?
|
||||||
char call[10]; // APRS callsign
|
char call[10]; // APRS callsign
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -1,471 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
// original source: https://github.com/Nkawu/TFT22_ILI9225
|
|
||||||
|
|
||||||
#ifndef TFT22_ILI9225_h
|
|
||||||
#define TFT22_ILI9225_h
|
|
||||||
|
|
||||||
#ifdef __STM32F1__
|
|
||||||
#define ARDUINO_STM32_FEATHER
|
|
||||||
#define PROGMEM
|
|
||||||
// if 'SPI_CHANNEL' is not defined, 'SPI' is used, only valid for STM32F1
|
|
||||||
//#define SPI_CHANNEL SPI_2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USE_STRING_CLASS
|
|
||||||
|
|
||||||
#ifdef USE_STRING_CLASS
|
|
||||||
#define STRING String
|
|
||||||
#else
|
|
||||||
#define STRING const char *
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ARDUINO >= 100
|
|
||||||
#include "Arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
#include <SPI.h>
|
|
||||||
#include "gfxfont.h"
|
|
||||||
|
|
||||||
#if defined(ARDUINO_STM32_FEATHER) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(STM32F1)
|
|
||||||
typedef volatile uint32 RwReg;
|
|
||||||
#endif
|
|
||||||
#if defined(ARDUINO_FEATHER52)
|
|
||||||
typedef volatile uint32_t RwReg;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ILI9225 screen size */
|
|
||||||
#define ILI9225_LCD_WIDTH 176
|
|
||||||
#define ILI9225_LCD_HEIGHT 220
|
|
||||||
|
|
||||||
/* ILI9225 LCD Registers */
|
|
||||||
#define ILI9225_DRIVER_OUTPUT_CTRL (0x01u) // Driver Output Control
|
|
||||||
#define ILI9225_LCD_AC_DRIVING_CTRL (0x02u) // LCD AC Driving Control
|
|
||||||
#define ILI9225_ENTRY_MODE (0x03u) // Entry Mode
|
|
||||||
#define ILI9225_DISP_CTRL1 (0x07u) // Display Control 1
|
|
||||||
#define ILI9225_BLANK_PERIOD_CTRL1 (0x08u) // Blank Period Control
|
|
||||||
#define ILI9225_FRAME_CYCLE_CTRL (0x0Bu) // Frame Cycle Control
|
|
||||||
#define ILI9225_INTERFACE_CTRL (0x0Cu) // Interface Control
|
|
||||||
#define ILI9225_OSC_CTRL (0x0Fu) // Osc Control
|
|
||||||
#define ILI9225_POWER_CTRL1 (0x10u) // Power Control 1
|
|
||||||
#define ILI9225_POWER_CTRL2 (0x11u) // Power Control 2
|
|
||||||
#define ILI9225_POWER_CTRL3 (0x12u) // Power Control 3
|
|
||||||
#define ILI9225_POWER_CTRL4 (0x13u) // Power Control 4
|
|
||||||
#define ILI9225_POWER_CTRL5 (0x14u) // Power Control 5
|
|
||||||
#define ILI9225_VCI_RECYCLING (0x15u) // VCI Recycling
|
|
||||||
#define ILI9225_RAM_ADDR_SET1 (0x20u) // Horizontal GRAM Address Set
|
|
||||||
#define ILI9225_RAM_ADDR_SET2 (0x21u) // Vertical GRAM Address Set
|
|
||||||
#define ILI9225_GRAM_DATA_REG (0x22u) // GRAM Data Register
|
|
||||||
#define ILI9225_GATE_SCAN_CTRL (0x30u) // Gate Scan Control Register
|
|
||||||
#define ILI9225_VERTICAL_SCROLL_CTRL1 (0x31u) // Vertical Scroll Control 1 Register
|
|
||||||
#define ILI9225_VERTICAL_SCROLL_CTRL2 (0x32u) // Vertical Scroll Control 2 Register
|
|
||||||
#define ILI9225_VERTICAL_SCROLL_CTRL3 (0x33u) // Vertical Scroll Control 3 Register
|
|
||||||
#define ILI9225_PARTIAL_DRIVING_POS1 (0x34u) // Partial Driving Position 1 Register
|
|
||||||
#define ILI9225_PARTIAL_DRIVING_POS2 (0x35u) // Partial Driving Position 2 Register
|
|
||||||
#define ILI9225_HORIZONTAL_WINDOW_ADDR1 (0x36u) // Horizontal Address Start Position
|
|
||||||
#define ILI9225_HORIZONTAL_WINDOW_ADDR2 (0x37u) // Horizontal Address End Position
|
|
||||||
#define ILI9225_VERTICAL_WINDOW_ADDR1 (0x38u) // Vertical Address Start Position
|
|
||||||
#define ILI9225_VERTICAL_WINDOW_ADDR2 (0x39u) // Vertical Address End Position
|
|
||||||
#define ILI9225_GAMMA_CTRL1 (0x50u) // Gamma Control 1
|
|
||||||
#define ILI9225_GAMMA_CTRL2 (0x51u) // Gamma Control 2
|
|
||||||
#define ILI9225_GAMMA_CTRL3 (0x52u) // Gamma Control 3
|
|
||||||
#define ILI9225_GAMMA_CTRL4 (0x53u) // Gamma Control 4
|
|
||||||
#define ILI9225_GAMMA_CTRL5 (0x54u) // Gamma Control 5
|
|
||||||
#define ILI9225_GAMMA_CTRL6 (0x55u) // Gamma Control 6
|
|
||||||
#define ILI9225_GAMMA_CTRL7 (0x56u) // Gamma Control 7
|
|
||||||
#define ILI9225_GAMMA_CTRL8 (0x57u) // Gamma Control 8
|
|
||||||
#define ILI9225_GAMMA_CTRL9 (0x58u) // Gamma Control 9
|
|
||||||
#define ILI9225_GAMMA_CTRL10 (0x59u) // Gamma Control 10
|
|
||||||
|
|
||||||
#define ILI9225C_INVOFF 0x20
|
|
||||||
#define ILI9225C_INVON 0x21
|
|
||||||
|
|
||||||
// autoincrement modes (register ILI9225_ENTRY_MODE, bit 5..3 )
|
|
||||||
enum autoIncMode_t { R2L_BottomUp, BottomUp_R2L, L2R_BottomUp, BottomUp_L2R, R2L_TopDown, TopDown_R2L, L2R_TopDown, TopDown_L2R };
|
|
||||||
|
|
||||||
/* RGB 16-bit color table definition (RG565) */
|
|
||||||
#define COLOR_BLACK 0x0000 /* 0, 0, 0 */
|
|
||||||
#define COLOR_WHITE 0xFFFF /* 255, 255, 255 */
|
|
||||||
#define COLOR_BLUE 0x001F /* 0, 0, 255 */
|
|
||||||
#define COLOR_GREEN 0x07E0 /* 0, 255, 0 */
|
|
||||||
#define COLOR_RED 0xF800 /* 255, 0, 0 */
|
|
||||||
#define COLOR_NAVY 0x000F /* 0, 0, 128 */
|
|
||||||
#define COLOR_DARKBLUE 0x0011 /* 0, 0, 139 */
|
|
||||||
#define COLOR_DARKGREEN 0x03E0 /* 0, 128, 0 */
|
|
||||||
#define COLOR_DARKCYAN 0x03EF /* 0, 128, 128 */
|
|
||||||
#define COLOR_CYAN 0x07FF /* 0, 255, 255 */
|
|
||||||
#define COLOR_TURQUOISE 0x471A /* 64, 224, 208 */
|
|
||||||
#define COLOR_INDIGO 0x4810 /* 75, 0, 130 */
|
|
||||||
#define COLOR_DARKRED 0x8000 /* 128, 0, 0 */
|
|
||||||
#define COLOR_OLIVE 0x7BE0 /* 128, 128, 0 */
|
|
||||||
#define COLOR_GRAY 0x8410 /* 128, 128, 128 */
|
|
||||||
#define COLOR_GREY 0x8410 /* 128, 128, 128 */
|
|
||||||
#define COLOR_SKYBLUE 0x867D /* 135, 206, 235 */
|
|
||||||
#define COLOR_BLUEVIOLET 0x895C /* 138, 43, 226 */
|
|
||||||
#define COLOR_LIGHTGREEN 0x9772 /* 144, 238, 144 */
|
|
||||||
#define COLOR_DARKVIOLET 0x901A /* 148, 0, 211 */
|
|
||||||
#define COLOR_YELLOWGREEN 0x9E66 /* 154, 205, 50 */
|
|
||||||
#define COLOR_BROWN 0xA145 /* 165, 42, 42 */
|
|
||||||
#define COLOR_DARKGRAY 0x7BEF /* 128, 128, 128 */
|
|
||||||
#define COLOR_DARKGREY 0x7BEF /* 128, 128, 128 */
|
|
||||||
#define COLOR_SIENNA 0xA285 /* 160, 82, 45 */
|
|
||||||
#define COLOR_LIGHTBLUE 0xAEDC /* 172, 216, 230 */
|
|
||||||
#define COLOR_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
|
|
||||||
#define COLOR_SILVER 0xC618 /* 192, 192, 192 */
|
|
||||||
#define COLOR_LIGHTGRAY 0xC618 /* 192, 192, 192 */
|
|
||||||
#define COLOR_LIGHTGREY 0xC618 /* 192, 192, 192 */
|
|
||||||
#define COLOR_LIGHTCYAN 0xE7FF /* 224, 255, 255 */
|
|
||||||
#define COLOR_VIOLET 0xEC1D /* 238, 130, 238 */
|
|
||||||
#define COLOR_AZUR 0xF7FF /* 240, 255, 255 */
|
|
||||||
#define COLOR_BEIGE 0xF7BB /* 245, 245, 220 */
|
|
||||||
#define COLOR_MAGENTA 0xF81F /* 255, 0, 255 */
|
|
||||||
#define COLOR_TOMATO 0xFB08 /* 255, 99, 71 */
|
|
||||||
#define COLOR_GOLD 0xFEA0 /* 255, 215, 0 */
|
|
||||||
#define COLOR_ORANGE 0xFD20 /* 255, 165, 0 */
|
|
||||||
#define COLOR_SNOW 0xFFDF /* 255, 250, 250 */
|
|
||||||
#define COLOR_YELLOW 0xFFE0 /* 255, 255, 0 */
|
|
||||||
|
|
||||||
|
|
||||||
/* Font defines */
|
|
||||||
#define FONT_HEADER_SIZE 4 // 1: pixel width of 1 font character, 2: pixel height,
|
|
||||||
#define readFontByte(x) pgm_read_byte(&cfont.font[x])
|
|
||||||
|
|
||||||
extern uint8_t Terminal6x8[];
|
|
||||||
extern uint8_t Terminal11x16[];
|
|
||||||
extern uint8_t Terminal12x16[];
|
|
||||||
extern uint8_t Trebuchet_MS16x21[];
|
|
||||||
|
|
||||||
struct _currentFont
|
|
||||||
{
|
|
||||||
uint8_t* font;
|
|
||||||
uint8_t width;
|
|
||||||
uint8_t height;
|
|
||||||
uint8_t offset;
|
|
||||||
uint8_t numchars;
|
|
||||||
uint8_t nbrows;
|
|
||||||
bool monoSp;
|
|
||||||
};
|
|
||||||
#define MONOSPACE 1
|
|
||||||
|
|
||||||
#if defined (ARDUINO_STM32_FEATHER)
|
|
||||||
#undef USE_FAST_PINIO
|
|
||||||
#elif defined (__AVR__) || defined(TEENSYDUINO) || defined(ESP8266) || defined(__arm__)
|
|
||||||
#define USE_FAST_PINIO
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Main and core class
|
|
||||||
class TFT22_ILI9225 {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
TFT22_ILI9225(int8_t RST, int8_t RS, int8_t CS, int8_t SDI, int8_t CLK, int8_t LED);
|
|
||||||
TFT22_ILI9225(int8_t RST, int8_t RS, int8_t CS, int8_t LED);
|
|
||||||
TFT22_ILI9225(int8_t RST, int8_t RS, int8_t CS, int8_t SDI, int8_t CLK, int8_t LED, uint8_t brightness);
|
|
||||||
TFT22_ILI9225(int8_t RST, int8_t RS, int8_t CS, int8_t LED, uint8_t brightness);
|
|
||||||
|
|
||||||
/// Initialization
|
|
||||||
#ifndef ESP32
|
|
||||||
void begin(void);
|
|
||||||
#else
|
|
||||||
void begin(SPIClass &spi=SPI);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Clear the screen
|
|
||||||
void clear(void);
|
|
||||||
|
|
||||||
/// Invert screen
|
|
||||||
/// @param flag true to invert, false for normal screen
|
|
||||||
void invert(boolean flag);
|
|
||||||
|
|
||||||
/// Switch backlight on or off
|
|
||||||
/// @param flag true=on, false=off
|
|
||||||
void setBacklight(boolean flag);
|
|
||||||
|
|
||||||
/// Set backlight brightness
|
|
||||||
/// @param brightness sets backlight brightness 0-255
|
|
||||||
void setBacklightBrightness(uint8_t brightness);
|
|
||||||
|
|
||||||
/// Switch display on or off
|
|
||||||
/// @param flag true=on, false=off
|
|
||||||
void setDisplay(boolean flag);
|
|
||||||
|
|
||||||
/// Set orientation
|
|
||||||
/// @param orientation orientation, 0=portrait, 1=right rotated landscape, 2=reverse portrait, 3=left rotated landscape
|
|
||||||
void setOrientation(uint8_t orientation);
|
|
||||||
|
|
||||||
/// Get orientation
|
|
||||||
/// @return orientation orientation, 0=portrait, 1=right rotated landscape, 2=reverse portrait, 3=left rotated landscape
|
|
||||||
uint8_t getOrientation(void);
|
|
||||||
|
|
||||||
/// Font size, x-axis
|
|
||||||
/// @return horizontal size of current font, in pixels
|
|
||||||
// uint8_t fontX(void);
|
|
||||||
|
|
||||||
/// Font size, y-axis
|
|
||||||
/// @return vertical size of current font, in pixels
|
|
||||||
// uint8_t fontY(void);
|
|
||||||
|
|
||||||
/// Screen size, x-axis
|
|
||||||
/// @return horizontal size of the screen, in pixels
|
|
||||||
/// @note 240 means 240 pixels and thus 0..239 coordinates (decimal)
|
|
||||||
uint16_t maxX(void);
|
|
||||||
|
|
||||||
/// Screen size, y-axis
|
|
||||||
/// @return vertical size of the screen, in pixels
|
|
||||||
/// @note 220 means 220 pixels and thus 0..219 coordinates (decimal)
|
|
||||||
uint16_t maxY(void);
|
|
||||||
|
|
||||||
/// Draw circle
|
|
||||||
/// @param x0 center, point coordinate, x-axis
|
|
||||||
/// @param y0 center, point coordinate, y-axis
|
|
||||||
/// @param radius radius
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw solid circle
|
|
||||||
/// @param x0 center, point coordinate, x-axis
|
|
||||||
/// @param y0 center, point coordinate, y-axis
|
|
||||||
/// @param radius radius
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void fillCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color);
|
|
||||||
|
|
||||||
/// Set background color
|
|
||||||
/// @param color background color, default=black
|
|
||||||
void setBackgroundColor(uint16_t color = COLOR_BLACK);
|
|
||||||
|
|
||||||
/// Draw line, rectangle coordinates
|
|
||||||
/// @param x1 start point coordinate, x-axis
|
|
||||||
/// @param y1 start point coordinate, y-axis
|
|
||||||
/// @param x2 end point coordinate, x-axis
|
|
||||||
/// @param y2 end point coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw rectangle, rectangle coordinates
|
|
||||||
/// @param x1 top left coordinate, x-axis
|
|
||||||
/// @param y1 top left coordinate, y-axis
|
|
||||||
/// @param x2 bottom right coordinate, x-axis
|
|
||||||
/// @param y2 bottom right coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw solid rectangle, rectangle coordinates
|
|
||||||
/// @param x1 top left coordinate, x-axis
|
|
||||||
/// @param y1 top left coordinate, y-axis
|
|
||||||
/// @param x2 bottom right coordinate, x-axis
|
|
||||||
/// @param y2 bottom right coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void fillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw pixel
|
|
||||||
/// @param x1 point coordinate, x-axis
|
|
||||||
/// @param y1 point coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawPixel(uint16_t x1, uint16_t y1, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw ASCII Text (pixel coordinates)
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param s text string
|
|
||||||
/// @param color 16-bit color, default=white
|
|
||||||
/// @return x-position behind text
|
|
||||||
uint16_t drawText(uint16_t x, uint16_t y, STRING s, uint16_t color = COLOR_WHITE);
|
|
||||||
|
|
||||||
/// width of an ASCII Text (pixel )
|
|
||||||
/// @param s text string
|
|
||||||
uint16_t getTextWidth( STRING s ) ;
|
|
||||||
|
|
||||||
/// Calculate 16-bit color from 8-bit Red-Green-Blue components
|
|
||||||
/// @param red red component, 0x00..0xff
|
|
||||||
/// @param green green component, 0x00..0xff
|
|
||||||
/// @param blue blue component, 0x00..0xff
|
|
||||||
/// @return 16-bit color
|
|
||||||
uint16_t setColor(uint8_t red, uint8_t green, uint8_t blue);
|
|
||||||
|
|
||||||
/// Calculate 8-bit Red-Green-Blue components from 16-bit color
|
|
||||||
/// @param rgb 16-bit color
|
|
||||||
/// @param red red component, 0x00..0xff
|
|
||||||
/// @param green green component, 0x00..0xff
|
|
||||||
/// @param blue blue component, 0x00..0xff
|
|
||||||
void splitColor(uint16_t rgb, uint8_t &red, uint8_t &green, uint8_t &blue);
|
|
||||||
|
|
||||||
/// Draw triangle, triangle coordinates
|
|
||||||
/// @param x1 corner 1 coordinate, x-axis
|
|
||||||
/// @param y1 corner 1 coordinate, y-axis
|
|
||||||
/// @param x2 corner 2 coordinate, x-axis
|
|
||||||
/// @param y2 corner 2 coordinate, y-axis
|
|
||||||
/// @param x3 corner 3 coordinate, x-axis
|
|
||||||
/// @param y3 corner 3 coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color);
|
|
||||||
|
|
||||||
/// Draw solid triangle, triangle coordinates
|
|
||||||
/// @param x1 corner 1 coordinate, x-axis
|
|
||||||
/// @param y1 corner 1 coordinate, y-axis
|
|
||||||
/// @param x2 corner 2 coordinate, x-axis
|
|
||||||
/// @param y2 corner 2 coordinate, y-axis
|
|
||||||
/// @param x3 corner 3 coordinate, x-axis
|
|
||||||
/// @param y3 corner 3 coordinate, y-axis
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void fillTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color);
|
|
||||||
|
|
||||||
/// Set current font
|
|
||||||
/// @param font Font name
|
|
||||||
void setFont(uint8_t* font, bool monoSp=false ); // default = proportional
|
|
||||||
|
|
||||||
/// Get current font
|
|
||||||
_currentFont getFont();
|
|
||||||
|
|
||||||
/// Draw single character (pixel coordinates)
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param ch ASCII character
|
|
||||||
/// @param color 16-bit color, default=white
|
|
||||||
/// @return width of character in display pixels
|
|
||||||
uint16_t drawChar(uint16_t x, uint16_t y, uint16_t ch, uint16_t color = COLOR_WHITE);
|
|
||||||
|
|
||||||
/// width of an ASCII character (pixel )
|
|
||||||
/// @param ch ASCII character
|
|
||||||
uint16_t getCharWidth( uint16_t ch ) ;
|
|
||||||
|
|
||||||
/// Draw bitmap
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param bitmap
|
|
||||||
/// @param w width
|
|
||||||
/// @param h height
|
|
||||||
/// @param color 16-bit color, default=white
|
|
||||||
/// @param bg 16-bit color, background
|
|
||||||
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
|
|
||||||
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg);
|
|
||||||
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
|
|
||||||
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg);
|
|
||||||
|
|
||||||
void drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
|
|
||||||
void drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg);
|
|
||||||
|
|
||||||
/// Draw bitmap
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param bitmap, 2D 16bit color bitmap
|
|
||||||
/// @param w width
|
|
||||||
/// @param h height
|
|
||||||
void drawBitmap(uint16_t x, uint16_t y, const uint16_t** bitmap, int16_t w, int16_t h);
|
|
||||||
void drawBitmap(uint16_t x, uint16_t y, uint16_t** bitmap, int16_t w, int16_t h);
|
|
||||||
|
|
||||||
/// Draw bitmap
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param bitmap, 1D 16bit color bitmap
|
|
||||||
/// @param w width
|
|
||||||
/// @param h height
|
|
||||||
void drawBitmap(uint16_t x, uint16_t y, const uint16_t* bitmap, int16_t w, int16_t h);
|
|
||||||
void drawBitmap(uint16_t x, uint16_t y, uint16_t* bitmap, int16_t w, int16_t h);
|
|
||||||
|
|
||||||
/// Set current GFX font
|
|
||||||
/// @param f GFX font name defined in include file
|
|
||||||
void setGFXFont(const GFXfont *f = NULL);
|
|
||||||
|
|
||||||
/// Draw a string with the current GFX font
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param s string to print
|
|
||||||
/// @param color 16-bit color
|
|
||||||
void drawGFXText(int16_t x, int16_t y, STRING s, uint16_t color);
|
|
||||||
|
|
||||||
/// Get the width & height of a text string with the current GFX font
|
|
||||||
/// @param str string to analyze
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param w width in pixels of string
|
|
||||||
/// @param h height in pixels of string
|
|
||||||
void getGFXTextExtent(STRING str, int16_t x, int16_t y, int16_t *w, int16_t *h);
|
|
||||||
|
|
||||||
/// Draw a single character with the current GFX font
|
|
||||||
/// @param x point coordinate, x-axis
|
|
||||||
/// @param y point coordinate, y-axis
|
|
||||||
/// @param c character to draw
|
|
||||||
/// @param color 16-bit color
|
|
||||||
/// @return width of character in display pixels
|
|
||||||
uint16_t drawGFXChar(int16_t x, int16_t y, unsigned char c, uint16_t color);
|
|
||||||
|
|
||||||
uint16_t drawGFXcharBM(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t *bm, int bmwidth, int bmheight);
|
|
||||||
|
|
||||||
void getGFXCharExtent(uint8_t c, int16_t *gw, int16_t *gh, int16_t *xa);
|
|
||||||
|
|
||||||
void setModeFlip(uint16_t m);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void _spiWrite(uint8_t v);
|
|
||||||
void _spiWrite16(uint16_t v);
|
|
||||||
void _spiWriteCommand(uint8_t c);
|
|
||||||
void _spiWriteData(uint8_t d);
|
|
||||||
|
|
||||||
void _swap(uint16_t &a, uint16_t &b);
|
|
||||||
void _setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
|
||||||
void _setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, autoIncMode_t mode);
|
|
||||||
void _resetWindow();
|
|
||||||
void _drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h,
|
|
||||||
uint16_t color, uint16_t bg, bool transparent, bool progmem, bool Xbit );
|
|
||||||
void _orientCoordinates(uint16_t &x1, uint16_t &y1);
|
|
||||||
void _writeRegister(uint16_t reg, uint16_t data);
|
|
||||||
void _writeData(uint8_t HI, uint8_t LO);
|
|
||||||
void _writeData16(uint16_t HILO);
|
|
||||||
void _writeCommand(uint8_t HI, uint8_t LO);
|
|
||||||
void _writeCommand16(uint16_t HILO);
|
|
||||||
uint16_t _maxX, _maxY, _bgColor;
|
|
||||||
|
|
||||||
#if defined (__AVR__) || defined(TEENSYDUINO)
|
|
||||||
int8_t _rst, _rs, _cs, _sdi, _clk, _led;
|
|
||||||
#ifdef USE_FAST_PINIO
|
|
||||||
volatile uint8_t *mosiport, *clkport, *dcport, *rsport, *csport;
|
|
||||||
uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask;
|
|
||||||
#endif
|
|
||||||
#elif defined (__arm__)
|
|
||||||
int32_t _rst, _rs, _cs, _sdi, _clk, _led;
|
|
||||||
#ifdef USE_FAST_PINIO
|
|
||||||
volatile RwReg *mosiport, *clkport, *dcport, *rsport, *csport;
|
|
||||||
uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask;
|
|
||||||
#endif
|
|
||||||
#elif defined (ESP8266) || defined (ESP32)
|
|
||||||
int8_t _rst, _rs, _cs, _sdi, _clk, _led;
|
|
||||||
#ifdef USE_FAST_PINIO
|
|
||||||
volatile uint32_t *mosiport, *clkport, *dcport, *rsport, *csport;
|
|
||||||
uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask;
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
int8_t _rst, _rs, _cs, _sdi, _clk, _led;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t _orientation, _brightness;
|
|
||||||
uint16_t _modeFlip;
|
|
||||||
|
|
||||||
// correspondig modes if orientation changed:
|
|
||||||
const autoIncMode_t modeTab [3][8] = {
|
|
||||||
// { R2L_BottomUp, BottomUp_R2L, L2R_BottomUp, BottomUp_L2R, R2L_TopDown, TopDown_R2L, L2R_TopDown, TopDown_L2R }//
|
|
||||||
/* 90° */ { BottomUp_L2R, L2R_BottomUp, TopDown_L2R, L2R_TopDown, BottomUp_R2L, R2L_BottomUp, TopDown_R2L, R2L_TopDown },
|
|
||||||
/*180° */ { L2R_TopDown , TopDown_L2R, R2L_TopDown, TopDown_R2L, L2R_BottomUp, BottomUp_L2R, R2L_BottomUp, BottomUp_R2L},
|
|
||||||
/*270° */ { TopDown_R2L , R2L_TopDown, BottomUp_R2L, R2L_BottomUp, TopDown_L2R, L2R_TopDown, BottomUp_L2R, L2R_BottomUp}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool hwSPI, blState;
|
|
||||||
|
|
||||||
_currentFont cfont;
|
|
||||||
|
|
||||||
#ifdef ESP32
|
|
||||||
SPIClass _spi;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint32_t writeFunctionLevel;
|
|
||||||
void startWrite(void);
|
|
||||||
void endWrite(void);
|
|
||||||
|
|
||||||
|
|
||||||
GFXfont *gfxFont;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "aprs.h"
|
#include "aprs.h"
|
||||||
|
#include "RS41.h"
|
||||||
|
|
||||||
extern const char *version_name;
|
extern const char *version_name;
|
||||||
extern const char *version_id;
|
extern const char *version_id;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
|
|
||||||
#ifndef _aprs_h
|
#ifndef _aprs_h
|
||||||
#define _aprs_h
|
#define _aprs_h
|
||||||
|
|
||||||
#include "Sonde.h"
|
#include "Sonde.h"
|
||||||
#include "RS41.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define APRS_MAXLEN 201
|
#define APRS_MAXLEN 201
|
||||||
|
|
|
@ -0,0 +1,320 @@
|
||||||
|
#include "../features.h"
|
||||||
|
|
||||||
|
#if FEATURE_APRS
|
||||||
|
|
||||||
|
#include "conn-aprs.h"
|
||||||
|
#include "aprs.h"
|
||||||
|
#include "posinfo.h"
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <lwip/dns.h>
|
||||||
|
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
// KISS over TCP for communicating with APRSdroid
|
||||||
|
static WiFiServer tncserver(14580);
|
||||||
|
static WiFiClient tncclient;
|
||||||
|
|
||||||
|
// APRS over TCP for radiosondy.info etc
|
||||||
|
static int tcpclient = 0;
|
||||||
|
enum { TCS_DISCONNECTED, TCS_DNSLOOKUP, TCS_DNSRESOLVED, TCS_CONNECTING, TCS_LOGIN, TCS_CONNECTED };
|
||||||
|
static uint8_t tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
ip_addr_t tcpclient_ipaddr;
|
||||||
|
|
||||||
|
extern const char *version_name;
|
||||||
|
extern const char *version_id;
|
||||||
|
|
||||||
|
extern WiFiUDP udp;
|
||||||
|
|
||||||
|
static unsigned long last_in = 0;
|
||||||
|
|
||||||
|
void tcpclient_fsm();
|
||||||
|
|
||||||
|
|
||||||
|
void ConnAPRS::init() {
|
||||||
|
aprs_gencrctab();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnAPRS::netsetup() {
|
||||||
|
// Setup for KISS TCP server
|
||||||
|
if(sonde.config.kisstnc.active) {
|
||||||
|
MDNS.addService("kiss-tnc", "tcp", 14580);
|
||||||
|
tncserver.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sonde.config.tcpfeed.active) {
|
||||||
|
// start the FSM
|
||||||
|
tcpclient_fsm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnAPRS::updateSonde( SondeInfo *si ) {
|
||||||
|
// prepare data (for UDP and TCP output)
|
||||||
|
char *str = aprs_senddata(si, sonde.config.call, sonde.config.objcall, sonde.config.udpfeed.symbol);
|
||||||
|
|
||||||
|
// Output via AXUDP
|
||||||
|
if(sonde.config.udpfeed.active) {
|
||||||
|
char raw[201];
|
||||||
|
int rawlen = aprsstr_mon2raw(str, raw, APRS_MAXLEN);
|
||||||
|
Serial.println("Sending AXUDP");
|
||||||
|
//Serial.println(raw);
|
||||||
|
udp.beginPacket(sonde.config.udpfeed.host, sonde.config.udpfeed.port);
|
||||||
|
udp.write((const uint8_t *)raw, rawlen);
|
||||||
|
udp.endPacket();
|
||||||
|
}
|
||||||
|
// KISS via TCP (incoming connection, e.g. from APRSdroid
|
||||||
|
if (tncclient.connected()) {
|
||||||
|
Serial.println("Sending position via TCP");
|
||||||
|
char raw[201];
|
||||||
|
int rawlen = aprsstr_mon2kiss(str, raw, APRS_MAXLEN);
|
||||||
|
Serial.print("sending: "); Serial.println(raw);
|
||||||
|
tncclient.write(raw, rawlen);
|
||||||
|
}
|
||||||
|
// APRS via TCP (outgoing connection to aprs-is, e.g. radiosonde.info or wettersonde.net
|
||||||
|
if (sonde.config.tcpfeed.active) {
|
||||||
|
static unsigned long lasttcp = 0;
|
||||||
|
tcpclient_fsm();
|
||||||
|
if(tcpclient_state == TCS_CONNECTED) {
|
||||||
|
unsigned long now = millis();
|
||||||
|
long tts = sonde.config.tcpfeed.highrate * 1000L - (now-lasttcp);
|
||||||
|
Serial.printf("aprs: now-last = %ld\n", (now - lasttcp));
|
||||||
|
if ( tts < 0 ) {
|
||||||
|
strcat(str, "\r\n");
|
||||||
|
Serial.printf("Sending APRS: %s",str);
|
||||||
|
write(tcpclient, str, strlen(str));
|
||||||
|
lasttcp = now;
|
||||||
|
} else {
|
||||||
|
Serial.printf("Sending APRS in %d s\n", (int)(tts/1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define APRS_TIMEOUT 25000
|
||||||
|
|
||||||
|
void ConnAPRS::updateStation( PosInfo *pi ) {
|
||||||
|
// This funciton is called peridocally.
|
||||||
|
|
||||||
|
// We check for stalled connection and possibly close it
|
||||||
|
Serial.printf("last_in - now: %ld\n", millis() - last_in);
|
||||||
|
if ( sonde.config.tcpfeed.timeout > 0) {
|
||||||
|
if ( last_in && ( (millis() - last_in) > sonde.config.tcpfeed.timeout*1000 ) ) {
|
||||||
|
Serial.println("APRS timeout - closing connection");
|
||||||
|
close(tcpclient);
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If available, read data from tcpclient; then send update (if its time for that)
|
||||||
|
tcpclient_fsm();
|
||||||
|
if(sonde.config.tcpfeed.active) {
|
||||||
|
aprs_station_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We check for new connections or new data (tnc port)
|
||||||
|
if (!tncclient.connected()) {
|
||||||
|
tncclient = tncserver.available();
|
||||||
|
if (tncclient.connected()) {
|
||||||
|
Serial.println("new TCP KISS connection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tncclient.available()) {
|
||||||
|
Serial.print("TCP KISS socket: recevied ");
|
||||||
|
while (tncclient.available()) {
|
||||||
|
Serial.print(tncclient.read()); // Check if we receive anything from from APRSdroid
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnAPRS::aprs_station_update() {
|
||||||
|
int chase = sonde.config.chase;
|
||||||
|
// automatically decided if CHASE or FIXED mode is used (for config AUTO)
|
||||||
|
if (chase == SH_LOC_AUTO) {
|
||||||
|
if (posInfo.chase) chase = SH_LOC_CHASE; else chase = SH_LOC_FIXED;
|
||||||
|
}
|
||||||
|
unsigned long time_now = millis();
|
||||||
|
unsigned long time_delta = time_now - time_last_aprs_update;
|
||||||
|
unsigned long update_time = (chase == SH_LOC_CHASE) ? APRS_MOBILE_STATION_UPDATE_TIME : APRS_STATION_UPDATE_TIME;
|
||||||
|
long tts = update_time - time_delta;
|
||||||
|
Serial.printf("aprs_statio_update due in %d s", (int)(tts/1000));
|
||||||
|
if (tts>0) return;
|
||||||
|
|
||||||
|
float lat, lon;
|
||||||
|
if (chase == SH_LOC_FIXED) {
|
||||||
|
// fixed location
|
||||||
|
lat = sonde.config.rxlat;
|
||||||
|
lon = sonde.config.rxlon;
|
||||||
|
if (isnan(lat) || isnan(lon)) return;
|
||||||
|
} else {
|
||||||
|
if (gpsPos.valid) {
|
||||||
|
lat = gpsPos.lat;
|
||||||
|
lon = gpsPos.lon;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char *bcn = aprs_send_beacon(sonde.config.call, lat, lon, sonde.config.beaconsym + ((chase == SH_LOC_CHASE) ? 2 : 0), sonde.config.comment);
|
||||||
|
tcpclient_fsm();
|
||||||
|
if(tcpclient_state == TCS_CONNECTED) {
|
||||||
|
strcat(bcn, "\r\n");
|
||||||
|
Serial.printf("APRS TCP BEACON: %s", bcn);
|
||||||
|
write(tcpclient, bcn, strlen(bcn));
|
||||||
|
time_last_aprs_update = time_now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tcp_dns_found(const char * name, const ip_addr_t *ipaddr, void * arg) {
|
||||||
|
if (ipaddr) {
|
||||||
|
tcpclient_ipaddr = *ipaddr;
|
||||||
|
tcpclient_state = TCS_DNSRESOLVED; // DNS lookup success
|
||||||
|
} else {
|
||||||
|
memset(&tcpclient_ipaddr, 0, sizeof(tcpclient_ipaddr));
|
||||||
|
tcpclient_state = TCS_DISCONNECTED; // DNS lookup failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcpclient_sendlogin() {
|
||||||
|
char buf[128];
|
||||||
|
snprintf(buf, 128, "user %s pass %d vers %s %s\r\n", sonde.config.call, sonde.config.passcode, version_name, version_id);
|
||||||
|
int res = write(tcpclient, buf, strlen(buf));
|
||||||
|
Serial.printf("APRS login: %s, res=%d\n", buf, res);
|
||||||
|
last_in = millis();
|
||||||
|
if(res<=0) {
|
||||||
|
close(tcpclient);
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcpclient_fsm() {
|
||||||
|
if(!sonde.config.tcpfeed.active)
|
||||||
|
return;
|
||||||
|
Serial.printf("TCS: %d\n", tcpclient_state);
|
||||||
|
|
||||||
|
fd_set fdset;
|
||||||
|
FD_ZERO(&fdset);
|
||||||
|
FD_SET(tcpclient, &fdset);
|
||||||
|
fd_set fdeset;
|
||||||
|
FD_ZERO(&fdeset);
|
||||||
|
FD_SET(tcpclient, &fdeset);
|
||||||
|
|
||||||
|
struct timeval selto = {0};
|
||||||
|
int res;
|
||||||
|
|
||||||
|
switch(tcpclient_state) {
|
||||||
|
case TCS_DISCONNECTED:
|
||||||
|
/* We are disconnected. Try to connect, starting with a DNS lookup */
|
||||||
|
{
|
||||||
|
// Restart timeout
|
||||||
|
last_in = millis();
|
||||||
|
err_t res = dns_gethostbyname( sonde.config.tcpfeed.host, &tcpclient_ipaddr, /*(dns_found_callback)*/_tcp_dns_found, NULL );
|
||||||
|
|
||||||
|
if(res == ERR_OK) { // Returns immediately of host is IP or in cache
|
||||||
|
tcpclient_state = TCS_DNSRESOLVED;
|
||||||
|
/* fall through */
|
||||||
|
} else if(res == ERR_INPROGRESS) {
|
||||||
|
tcpclient_state = TCS_DNSLOOKUP;
|
||||||
|
break;
|
||||||
|
} else { // failed
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case TCS_DNSRESOLVED:
|
||||||
|
{
|
||||||
|
/* We have got the IP address, start the connection */
|
||||||
|
tcpclient = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
int flags = fcntl(tcpclient, F_GETFL);
|
||||||
|
if (fcntl(tcpclient, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
Serial.println("Setting O_NONBLOCK failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in sock_info;
|
||||||
|
memset(&sock_info, 0, sizeof(struct sockaddr_in));
|
||||||
|
sock_info.sin_family = AF_INET;
|
||||||
|
sock_info.sin_addr.s_addr = tcpclient_ipaddr.u_addr.ip4.addr;
|
||||||
|
sock_info.sin_port = htons( sonde.config.tcpfeed.port );
|
||||||
|
err_t res = connect(tcpclient, (struct sockaddr *)&sock_info, sizeof(sock_info));
|
||||||
|
if(res) {
|
||||||
|
if (errno == EINPROGRESS) { // Should be the usual case, go to connecting state
|
||||||
|
tcpclient_state = TCS_CONNECTING;
|
||||||
|
} else {
|
||||||
|
close(tcpclient);
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcpclient_state = TCS_CONNECTED;
|
||||||
|
tcpclient_sendlogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TCS_CONNECTING:
|
||||||
|
{
|
||||||
|
// Poll to see if we are now connected
|
||||||
|
res = select(tcpclient+1, NULL, &fdset, &fdeset, &selto);
|
||||||
|
if(res<0) {
|
||||||
|
Serial.println("TNS_CONNECTING: select error");
|
||||||
|
goto error;
|
||||||
|
} else if (res==0) { // still pending
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Socket has become ready (or something went wrong, check for error first)
|
||||||
|
|
||||||
|
int sockerr;
|
||||||
|
socklen_t len = (socklen_t)sizeof(int);
|
||||||
|
if (getsockopt(tcpclient, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
Serial.printf("select returing %d. isset:%d iseset:%d sockerr:%d\n", res, FD_ISSET(tcpclient, &fdset), FD_ISSET(tcpclient, &fdeset), sockerr);
|
||||||
|
if(sockerr) {
|
||||||
|
Serial.printf("APRS connect error: %s\n", strerror(sockerr));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
tcpclient_state = TCS_CONNECTED;
|
||||||
|
tcpclient_sendlogin();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TCS_CONNECTED:
|
||||||
|
{
|
||||||
|
res = select(tcpclient+1, &fdset, NULL, NULL, &selto);
|
||||||
|
if(res<0) {
|
||||||
|
Serial.println("TCS_CONNECTING: select error");
|
||||||
|
goto error;
|
||||||
|
} else if (res==0) { // still pending
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Read data
|
||||||
|
char buf[512+1];
|
||||||
|
res = read(tcpclient, buf, 512);
|
||||||
|
if(res<=0) {
|
||||||
|
close(tcpclient);
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
} else {
|
||||||
|
buf[res] = 0;
|
||||||
|
Serial.printf("tcpclient data (len=%d):", res);
|
||||||
|
Serial.write( (uint8_t *)buf, res );
|
||||||
|
last_in = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TCS_DNSLOOKUP:
|
||||||
|
Serial.println("DNS lookup in progress");
|
||||||
|
break; // DNS lookup in progress, do not do anything until callback is called, updating the state
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
close(tcpclient);
|
||||||
|
tcpclient_state = TCS_DISCONNECTED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConnAPRS connAPRS;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_APRS
|
||||||
|
|
||||||
|
#ifndef conn_aprs_h
|
||||||
|
#define conn_aprs_h
|
||||||
|
|
||||||
|
#include "conn.h"
|
||||||
|
#include "aprs.h"
|
||||||
|
|
||||||
|
// Times in ms, i.e. station: 10 minutes, mobile: 20 seconds
|
||||||
|
#define APRS_STATION_UPDATE_TIME (10*60*1000)
|
||||||
|
#define APRS_MOBILE_STATION_UPDATE_TIME (20*1000)
|
||||||
|
|
||||||
|
static unsigned long time_last_aprs_update = -APRS_STATION_UPDATE_TIME;
|
||||||
|
|
||||||
|
|
||||||
|
class ConnAPRS : public Conn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Called once on startup */
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/* Called whenever the network becomes available */
|
||||||
|
void netsetup();
|
||||||
|
|
||||||
|
/* Called approx 1x / second (maybe only if good data is available) */
|
||||||
|
void updateSonde( SondeInfo *si );
|
||||||
|
|
||||||
|
/* Called approx 1x / second* */
|
||||||
|
void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void aprs_station_update();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ConnAPRS connAPRS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,8 +1,20 @@
|
||||||
#include "Chasemapper.h"
|
#include "../features.h"
|
||||||
|
#if FEATURE_CHASEMAPPER
|
||||||
|
|
||||||
|
#include "conn-chasemapper.h"
|
||||||
|
#include <WiFiUdp.h>
|
||||||
|
|
||||||
extern const char *sondeTypeStrSH[];
|
extern const char *sondeTypeStrSH[];
|
||||||
|
extern WiFiUDP udp;
|
||||||
|
|
||||||
int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
void ConnChasemapper::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnChasemapper::netsetup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConnChasemapper::updateSonde(SondeInfo *si) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct tm tim;
|
struct tm tim;
|
||||||
time_t t = si->d.time;
|
time_t t = si->d.time;
|
||||||
|
@ -11,8 +23,16 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
||||||
if (TYPE_IS_METEO(realtype)) {
|
if (TYPE_IS_METEO(realtype)) {
|
||||||
realtype = si->d.subtype == 1 ? STYPE_M10 : STYPE_M20;
|
realtype = si->d.subtype == 1 ? STYPE_M10 : STYPE_M20;
|
||||||
}
|
}
|
||||||
|
char prefix[10];
|
||||||
|
if(realtype == STYPE_RS41) {
|
||||||
|
prefix[0] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy(prefix, sondeTypeStrSH[realtype], 10);
|
||||||
|
strcat(prefix, "-");
|
||||||
|
}
|
||||||
sprintf(buf, "{ \"type\": \"PAYLOAD_SUMMARY\","
|
sprintf(buf, "{ \"type\": \"PAYLOAD_SUMMARY\","
|
||||||
"\"callsign\": \"%s\","
|
"\"callsign\": \"%s%s\","
|
||||||
"\"latitude\": %.5f,"
|
"\"latitude\": %.5f,"
|
||||||
"\"longitude\": %.5f,"
|
"\"longitude\": %.5f,"
|
||||||
"\"altitude\": %d,"
|
"\"altitude\": %d,"
|
||||||
|
@ -21,6 +41,7 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
||||||
"\"time\": \"%02d:%02d:%02d\","
|
"\"time\": \"%02d:%02d:%02d\","
|
||||||
"\"model\": \"%s\","
|
"\"model\": \"%s\","
|
||||||
"\"freq\": \"%.3f MHz\"",
|
"\"freq\": \"%.3f MHz\"",
|
||||||
|
prefix,
|
||||||
si->d.ser,
|
si->d.ser,
|
||||||
si->d.lat,
|
si->d.lat,
|
||||||
si->d.lon,
|
si->d.lon,
|
||||||
|
@ -38,6 +59,10 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
|
||||||
udp.beginPacket(sonde.config.cm.host, sonde.config.cm.port);
|
udp.beginPacket(sonde.config.cm.host, sonde.config.cm.port);
|
||||||
udp.write((const uint8_t *)buf, strlen(buf));
|
udp.write((const uint8_t *)buf, strlen(buf));
|
||||||
udp.endPacket();
|
udp.endPacket();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnChasemapper::updateStation(PosInfo *pi) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnChasemapper connChasemapper;
|
||||||
|
#endif
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef _CHASEMAPPER_H
|
||||||
|
#define _CHASEMAPPER_H
|
||||||
|
|
||||||
|
#include "Sonde.h"
|
||||||
|
#include "conn.h"
|
||||||
|
|
||||||
|
class ConnChasemapper : public Conn {
|
||||||
|
public:
|
||||||
|
void init();
|
||||||
|
void netsetup();
|
||||||
|
void updateSonde( SondeInfo *si );
|
||||||
|
void updateStation( PosInfo *pi );
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ConnChasemapper connChasemapper;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_MQTT
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "conn-mqtt.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncMqttClient.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include "json.h"
|
||||||
|
|
||||||
|
extern const char *version_name;
|
||||||
|
extern const char *version_id;
|
||||||
|
|
||||||
|
/* configuration paramters are in the config, no need to duplicate :-)
|
||||||
|
{"mqtt.active", 0, &sonde.config.mqtt.active},
|
||||||
|
{"mqtt.id", 63, &sonde.config.mqtt.id},
|
||||||
|
{"mqtt.host", 63, &sonde.config.mqtt.host},
|
||||||
|
{"mqtt.port", 0, &sonde.config.mqtt.port},
|
||||||
|
{"mqtt.username", 63, &sonde.config.mqtt.username},
|
||||||
|
{"mqtt.password", 63, &sonde.config.mqtt.password},
|
||||||
|
{"mqtt.prefix", 63, &sonde.config.mqtt.prefix},
|
||||||
|
*/
|
||||||
|
|
||||||
|
TimerHandle_t mqttReconnectTimer;
|
||||||
|
|
||||||
|
/* Global initalization (on TTGO startup) */
|
||||||
|
void MQTT::init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Internal helper function for netsetup
|
||||||
|
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
||||||
|
Serial.print("Message arrived [");
|
||||||
|
Serial.print(topic);
|
||||||
|
Serial.print("] ");
|
||||||
|
for (int i=0;i<length;i++) {
|
||||||
|
Serial.print((char)payload[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Network initialization (as soon as network becomes available) */
|
||||||
|
void MQTT::netsetup() {
|
||||||
|
if (!sonde.config.mqtt.active)
|
||||||
|
return;
|
||||||
|
if (strlen(sonde.config.mqtt.host)==0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
WiFi.hostByName(sonde.config.mqtt.host, this->ip);
|
||||||
|
|
||||||
|
Serial.println("[MQTT] pubsub client");
|
||||||
|
mqttClient.setServer(ip, sonde.config.mqtt.port);
|
||||||
|
snprintf(clientID, 20, "%s%04d", sonde.config.mqtt.id, (int)random(0, 1000));
|
||||||
|
clientID[20] = 0;
|
||||||
|
Serial.print(clientID);
|
||||||
|
mqttClient.setClientId(clientID);
|
||||||
|
if (strlen(sonde.config.mqtt.password) > 0) {
|
||||||
|
mqttClient.setCredentials(sonde.config.mqtt.username, sonde.config.mqtt.password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MQTT::updateSonde( SondeInfo *si ) {
|
||||||
|
if(!sonde.config.mqtt.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(1 /*connected*/) {
|
||||||
|
Serial.println("Sending sonde info via MQTT");
|
||||||
|
// TODO: Check if si is good / fresh
|
||||||
|
publishPacket(si);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MQTT::updateStation( PosInfo *pi ) {
|
||||||
|
if(!sonde.config.mqtt.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int now = millis();
|
||||||
|
if ( (lastMqttUptime == 0 || (lastMqttUptime + 60000 < now) || (lastMqttUptime > now))) {
|
||||||
|
publishUptime();
|
||||||
|
lastMqttUptime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal (private) functions
|
||||||
|
//void MQTT::connectToMqtt() {
|
||||||
|
// Serial.println("Connecting to MQTT...");
|
||||||
|
// mqttClient.connect();
|
||||||
|
//}
|
||||||
|
|
||||||
|
void MQTT::publishUptime()
|
||||||
|
{
|
||||||
|
mqttClient.connect(); // ensure we've got connection
|
||||||
|
|
||||||
|
Serial.println("[MQTT] writing");
|
||||||
|
char payload[256];
|
||||||
|
// maybe TODO: Use dynamic position if GPS is available?
|
||||||
|
// rxlat, rxlon only if not empty
|
||||||
|
snprintf(payload, 256, "{\"uptime\": %lu, \"user\": \"%s\", ", millis(), sonde.config.mqtt.username);
|
||||||
|
if( !isnan(sonde.config.rxlat) && !isnan(sonde.config.rxlon) ) {
|
||||||
|
snprintf(payload, 256, "%s\"rxlat\": %.5f, \"rxlon\": %.5f, ", payload, sonde.config.rxlat, sonde.config.rxlon);
|
||||||
|
}
|
||||||
|
snprintf(payload, 256, "%s\"SW\": \"%s\", \"VER\": \"%s\"}", payload, version_name, version_id);
|
||||||
|
Serial.println(payload);
|
||||||
|
char topic[128];
|
||||||
|
snprintf(topic, 128, "%s%s", sonde.config.mqtt.prefix, "uptime");
|
||||||
|
mqttClient.publish(topic, 1, 1, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MQTT::publishPacket(SondeInfo *si)
|
||||||
|
{
|
||||||
|
SondeData *s = &(si->d);
|
||||||
|
mqttClient.connect(); // ensure we've got connection
|
||||||
|
|
||||||
|
char payload[1024];
|
||||||
|
payload[0] = '{';
|
||||||
|
int n = sonde2json(payload+1, 1023, si);
|
||||||
|
if(n<0) {
|
||||||
|
// ERROR
|
||||||
|
Serial.println("publishPacket: sonde2json failed, string too long");
|
||||||
|
}
|
||||||
|
strcat(payload, "}"); // terminate payload string
|
||||||
|
|
||||||
|
char topic[128];
|
||||||
|
snprintf(topic, 128, "%s%s", sonde.config.mqtt.prefix, "packet");
|
||||||
|
Serial.print(payload);
|
||||||
|
mqttClient.publish(topic, 1, 1, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
MQTT connMQTT;
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_MQTT
|
||||||
|
|
||||||
|
#ifndef MQTT_h
|
||||||
|
#define MQTT_h
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <AsyncMqttClient.h>
|
||||||
|
#include "Sonde.h"
|
||||||
|
//#include "RS41.h"
|
||||||
|
#include "conn.h"
|
||||||
|
|
||||||
|
class MQTT : public Conn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Called once on startup */
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/* Called whenever the network becomes available */
|
||||||
|
void netsetup();
|
||||||
|
|
||||||
|
/* Called approx 1x / second (maybe only if good data is available) */
|
||||||
|
virtual void updateSonde( SondeInfo *si );
|
||||||
|
|
||||||
|
/* Called approx 1x / second* */
|
||||||
|
virtual void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
WiFiClient mqttWifiClient;
|
||||||
|
AsyncMqttClient mqttClient;
|
||||||
|
TimerHandle_t mqttReconnectTimer;
|
||||||
|
IPAddress ip;
|
||||||
|
//uint16_t port;
|
||||||
|
//const char *username;
|
||||||
|
//const char *password;
|
||||||
|
//const char *prefix;
|
||||||
|
char clientID[21];
|
||||||
|
|
||||||
|
//void init(const char *host, uint16_t port, const char *id, const char *username, const char *password, const char *prefix);
|
||||||
|
void publishPacket(SondeInfo *s);
|
||||||
|
void publishUptime();
|
||||||
|
//void connectToMqtt();
|
||||||
|
|
||||||
|
unsigned long lastMqttUptime = 0;
|
||||||
|
boolean mqttEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern MQTT connMQTT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,51 @@
|
||||||
|
#include "../features.h"
|
||||||
|
|
||||||
|
#if FEATURE_SDCARD
|
||||||
|
|
||||||
|
#include "conn-sdcard.h"
|
||||||
|
|
||||||
|
// TODO: Move into config
|
||||||
|
#define CS 13
|
||||||
|
#define SYNC_INTERVAL 10
|
||||||
|
|
||||||
|
void ConnSDCard::init() {
|
||||||
|
/* Initialize SD card */
|
||||||
|
initok = SD.begin(CS);
|
||||||
|
Serial.printf("SD card init: %s\n", initok?"OK":"Failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSDCard::netsetup() {
|
||||||
|
/* empty function, we don't use any network here */
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnSDCard::updateSonde( SondeInfo *si ) {
|
||||||
|
if (!initok) return;
|
||||||
|
if (!file) {
|
||||||
|
file = SD.open("/data.csv", FILE_APPEND);
|
||||||
|
}
|
||||||
|
if (!file) {
|
||||||
|
Serial.println("Error opening file");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SondeData *sd = &si->d;
|
||||||
|
file.printf("%d,%s,%s,%d,"
|
||||||
|
"%f,%f,%f,%f,%f,%f,%d,%d,"
|
||||||
|
"%d,%d,%d,%d\n",
|
||||||
|
sd->validID, sd->ser, sd->typestr, sd->subtype,
|
||||||
|
sd->lat, sd->lon, sd->alt, sd->vs, sd->hs, sd->dir, sd->sats, sd->validPos,
|
||||||
|
sd->time, sd->frame, sd->vframe, sd->validTime);
|
||||||
|
wcount++;
|
||||||
|
if(wcount >= SYNC_INTERVAL) {
|
||||||
|
file.flush();
|
||||||
|
wcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ConnSDCard::updateStation( PosInfo *pi ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConnSDCard connSDCard;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* conn-sdcard.h
|
||||||
|
* Data exporter to SD card
|
||||||
|
* Copyright (c) 2023 Hansi Reiser, dl9rdz
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef conn_sdcard_h
|
||||||
|
#define conn_sdcard_h
|
||||||
|
|
||||||
|
#include "conn.h"
|
||||||
|
|
||||||
|
//#include "FS.h"
|
||||||
|
#include "SD.h"
|
||||||
|
|
||||||
|
class ConnSDCard : public Conn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Called once on startup */
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/* Called whenever the network becomes available */
|
||||||
|
void netsetup();
|
||||||
|
|
||||||
|
|
||||||
|
/* Called approx 1x / second (maybe only if good data is available) */
|
||||||
|
virtual void updateSonde( SondeInfo *si );
|
||||||
|
|
||||||
|
/* Called approx 1x / second* */
|
||||||
|
virtual void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
File file;
|
||||||
|
uint8_t initok = 0;
|
||||||
|
uint16_t wcount = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* conn.h
|
||||||
|
* Interface for external data exporters
|
||||||
|
* Copyright (c) 2023 Hansi Reiser, dl9rdz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef conn_h
|
||||||
|
#define conn_h
|
||||||
|
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
|
|
||||||
|
// to be moved elsewhere
|
||||||
|
struct PosInfo {
|
||||||
|
public:
|
||||||
|
float lat;
|
||||||
|
float lon;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Interface for all data exporters */
|
||||||
|
class Conn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* Called once on startup */
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
|
/* Called whenever the network becomes available */
|
||||||
|
virtual void netsetup();
|
||||||
|
|
||||||
|
/* Called approx 1x / second (maybe only if good data is available) */
|
||||||
|
virtual void updateSonde( SondeInfo *si );
|
||||||
|
|
||||||
|
/* Called approx 1x / second* */
|
||||||
|
virtual void updateStation( PosInfo *pi );
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -1,3 +1,6 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_RS92
|
||||||
|
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "geteph.h"
|
#include "geteph.h"
|
||||||
#include <SPIFFS.h>
|
#include <SPIFFS.h>
|
||||||
|
@ -14,7 +17,7 @@ extern WiFiClient client;
|
||||||
char outbuf[128];
|
char outbuf[128];
|
||||||
uint8_t ephstate = EPH_NOTUSED;
|
uint8_t ephstate = EPH_NOTUSED;
|
||||||
//enum EPHSTATE { EPH_NOTUSED, EPH_PENDING, EPH_TIMEERR, EPH_ERROR, EPH_EPHERROR, EPH_GOOD };
|
//enum EPHSTATE { EPH_NOTUSED, EPH_PENDING, EPH_TIMEERR, EPH_ERROR, EPH_EPHERROR, EPH_GOOD };
|
||||||
const char *ephtxt[] = { "Disabled", "Pending", "Time error", "Fetch error", "Read error", "Good" };
|
const char *ephtxt[] = { "Disabled (no RS92 in QRG list or Wifi mode not 3)", "Pending", "Time error", "Fetch error", "Read error", "Good" };
|
||||||
|
|
||||||
uint8_t getreply() {
|
uint8_t getreply() {
|
||||||
String s = client.readStringUntil('\n');
|
String s = client.readStringUntil('\n');
|
||||||
|
@ -83,22 +86,25 @@ void geteph() {
|
||||||
Serial.println("cannot open file\n");
|
Serial.println("cannot open file\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char host[252];
|
char host[100];
|
||||||
strcpy(host, sonde.config.ephftp);
|
char buf[200];
|
||||||
char *buf = strchr(host, '/');
|
char *ptr = strchr(sonde.config.ephftp, '/');
|
||||||
if(!buf) { Serial.println("Invalid FTP host config"); return; }
|
if(!ptr) { Serial.println("Invalid FTP host config"); return; }
|
||||||
*buf = 0;
|
int hlen = ptr - sonde.config.ephftp;
|
||||||
buf++;
|
strncpy(host, sonde.config.ephftp, hlen);
|
||||||
|
host[hlen] = 0;
|
||||||
|
snprintf(buf, 200, ptr+1, year, day, year-2000);
|
||||||
uint8_t dispw, disph, dispxs, dispys;
|
uint8_t dispw, disph, dispxs, dispys;
|
||||||
disp.rdis->getDispSize(&disph, &dispw, &dispxs, &dispys);
|
disp.rdis->getDispSize(&disph, &dispw, &dispxs, &dispys);
|
||||||
disp.rdis->clear();
|
disp.rdis->clear();
|
||||||
disp.rdis->setFont(FONT_SMALL);
|
disp.rdis->setFont(FONT_SMALL);
|
||||||
disp.rdis->drawString(0, 0, host);
|
disp.rdis->drawString(0, 0, host);
|
||||||
// fetch rinex from server
|
// fetch rinex from server
|
||||||
char *ptr = buf + strlen(buf);
|
// char *ptr = buf + strlen(buf);
|
||||||
snprintf(ptr, 128, "%04d/%03d/brdc%03d0.%02dn.gz", year, day, day, year-2000);
|
// snprintf(ptr, 128, "%04d/%03d/brdc%03d0.%02dn.gz", year, day, day, year-2000);
|
||||||
|
// snprintf(ptr, 128, "%04d/brdc/brdc%03d0.%02dn.gz", year, /*day,*/ day, year-2000);
|
||||||
Serial.println("running geteph\n");
|
Serial.println("running geteph\n");
|
||||||
disp.rdis->drawString(0, 1*dispys, ptr+9);
|
disp.rdis->drawString(0, 1*dispys, buf+9);
|
||||||
|
|
||||||
if(!client.connect(host, 21)) {
|
if(!client.connect(host, 21)) {
|
||||||
Serial.printf("FTP connection to %s failed\n", host);
|
Serial.printf("FTP connection to %s failed\n", host);
|
||||||
|
@ -236,3 +242,4 @@ void geteph() {
|
||||||
file.close();
|
file.close();
|
||||||
ofile.close();
|
ofile.close();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,164 +0,0 @@
|
||||||
#include <Arduino.h>
|
|
||||||
#include "mqtt.h"
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <AsyncMqttClient.h>
|
|
||||||
#include <ESPmDNS.h>
|
|
||||||
#include "RS41.h"
|
|
||||||
#include "json.h"
|
|
||||||
|
|
||||||
extern const char *version_name;
|
|
||||||
extern const char *version_id;
|
|
||||||
|
|
||||||
TimerHandle_t mqttReconnectTimer;
|
|
||||||
|
|
||||||
void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
||||||
Serial.print("Message arrived [");
|
|
||||||
Serial.print(topic);
|
|
||||||
Serial.print("] ");
|
|
||||||
for (int i=0;i<length;i++) {
|
|
||||||
Serial.print((char)payload[i]);
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
static char buffer[21];
|
|
||||||
void MQTT::init(const char* host, uint16_t port, const char* id, const char *username, const char *password, const char *prefix)
|
|
||||||
{
|
|
||||||
WiFi.hostByName(host, this->ip);
|
|
||||||
this->port = port;
|
|
||||||
this->username = username;
|
|
||||||
this->password = password;
|
|
||||||
this->prefix = prefix;
|
|
||||||
|
|
||||||
Serial.println("[MQTT] pubsub client");
|
|
||||||
mqttClient.setServer(ip, port);
|
|
||||||
snprintf(buffer, 20, "%s%04d", id, (int)random(0, 1000));
|
|
||||||
buffer[20] = 0;
|
|
||||||
Serial.print(buffer);
|
|
||||||
mqttClient.setClientId(buffer);
|
|
||||||
if (strlen(password) > 0) {
|
|
||||||
mqttClient.setCredentials(username, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::connectToMqtt() {
|
|
||||||
Serial.println("Connecting to MQTT...");
|
|
||||||
mqttClient.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publishUptime()
|
|
||||||
{
|
|
||||||
mqttClient.connect(); // ensure we've got connection
|
|
||||||
|
|
||||||
Serial.println("[MQTT] writing");
|
|
||||||
char payload[256];
|
|
||||||
// maybe TODO: Use dynamic position if GPS is available?
|
|
||||||
// rxlat, rxlon only if not empty
|
|
||||||
snprintf(payload, 256, "{\"uptime\": %lu, \"user\": \"%s\", ", millis(), username);
|
|
||||||
if( !isnan(sonde.config.rxlat) && !isnan(sonde.config.rxlon) ) {
|
|
||||||
snprintf(payload, 256, "%s\"rxlat\": %.5f, \"rxlon\": %.5f, ", payload, sonde.config.rxlat, sonde.config.rxlon);
|
|
||||||
}
|
|
||||||
snprintf(payload, 256, "%s\"SW\": \"%s\", \"VER\": \"%s\"}", payload, version_name, version_id);
|
|
||||||
Serial.println(payload);
|
|
||||||
char topic[128];
|
|
||||||
snprintf(topic, 128, "%s%s", this->prefix, "uptime");
|
|
||||||
mqttClient.publish(topic, 1, 1, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MQTT::publishPacket(SondeInfo *si)
|
|
||||||
{
|
|
||||||
SondeData *s = &(si->d);
|
|
||||||
mqttClient.connect(); // ensure we've got connection
|
|
||||||
|
|
||||||
char payload[1024];
|
|
||||||
payload[0] = '{';
|
|
||||||
int n = sonde2json(payload+1, 1023, si);
|
|
||||||
if(n<0) {
|
|
||||||
// ERROR
|
|
||||||
Serial.println("publishPacket: sonde2json failed, string too long");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
snprintf(payload, 1024, "{"
|
|
||||||
"\"active\": %d,"
|
|
||||||
"\"freq\": %.2f,"
|
|
||||||
"\"id\": \"%s\","
|
|
||||||
"\"ser\": \"%s\","
|
|
||||||
"\"validId\": %d,"
|
|
||||||
"\"launchsite\": \"%s\","
|
|
||||||
"\"lat\": %.5f,"
|
|
||||||
"\"lon\": %.5f,"
|
|
||||||
"\"alt\": %.1f,"
|
|
||||||
"\"vs\": %.1f,"
|
|
||||||
"\"hs\": %.1f,"
|
|
||||||
"\"dir\": %.1f,"
|
|
||||||
"\"sats\": %d,"
|
|
||||||
"\"validPos\": %d,"
|
|
||||||
"\"time\": %u,"
|
|
||||||
"\"frame\": %u,"
|
|
||||||
"\"validTime\": %d,"
|
|
||||||
"\"rssi\": %d,"
|
|
||||||
"\"afc\": %d,"
|
|
||||||
"\"rxStat\": \"%s\","
|
|
||||||
"\"rxStart\": %u,"
|
|
||||||
"\"norxStart\": %u,"
|
|
||||||
"\"viewStart\": %u,"
|
|
||||||
"\"lastState\": %d,"
|
|
||||||
"\"launchKT\": %d,"
|
|
||||||
"\"burstKT\": %d,"
|
|
||||||
"\"countKT\": %d,"
|
|
||||||
"\"crefKT\": %d",
|
|
||||||
(int)si->active,
|
|
||||||
si->freq,
|
|
||||||
s->id,
|
|
||||||
s->ser,
|
|
||||||
(int)s->validID,
|
|
||||||
si->launchsite,
|
|
||||||
s->lat,
|
|
||||||
s->lon,
|
|
||||||
s->alt,
|
|
||||||
s->vs,
|
|
||||||
s->hs,
|
|
||||||
s->dir,
|
|
||||||
s->sats,
|
|
||||||
s->validPos,
|
|
||||||
s->time,
|
|
||||||
s->frame,
|
|
||||||
(int)s->validTime,
|
|
||||||
si->rssi,
|
|
||||||
si->afc,
|
|
||||||
si->rxStat,
|
|
||||||
si->rxStart,
|
|
||||||
si->norxStart,
|
|
||||||
si->viewStart,
|
|
||||||
si->lastState,
|
|
||||||
s->launchKT,
|
|
||||||
s->burstKT,
|
|
||||||
s->countKT,
|
|
||||||
s->crefKT
|
|
||||||
);
|
|
||||||
if ( !isnan( s->temperature ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"temp\": ", s->temperature );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->relativeHumidity ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"humidity\": ", s->relativeHumidity );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->pressure ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"pressure\": ", s->pressure );
|
|
||||||
}
|
|
||||||
if ( !isnan( s->batteryVoltage && s->batteryVoltage > 0 ) ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%.1f", payload, ",\"batt\": ", s->batteryVoltage );
|
|
||||||
}
|
|
||||||
char subtype[11];
|
|
||||||
if ( RS41::getSubtype( subtype, 11, si) == 0 ) {
|
|
||||||
snprintf(payload, 1024, "%s%s%s%s", payload, ",\"subtype\": \"", subtype, "\"" );
|
|
||||||
}
|
|
||||||
snprintf(payload, 1024, "%s%s", payload, "}" ); // terminate payload string
|
|
||||||
#endif
|
|
||||||
strcat(payload, "}"); // terminate payload string
|
|
||||||
|
|
||||||
char topic[128];
|
|
||||||
snprintf(topic, 128, "%s%s", this->prefix, "packet");
|
|
||||||
Serial.print(payload);
|
|
||||||
mqttClient.publish(topic, 1, 1, payload);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
#ifndef MQTT_h
|
|
||||||
#define MQTT_h
|
|
||||||
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <AsyncMqttClient.h>
|
|
||||||
#include "Sonde.h"
|
|
||||||
#include "RS41.h"
|
|
||||||
|
|
||||||
class MQTT
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WiFiClient mqttWifiClient;
|
|
||||||
AsyncMqttClient mqttClient;
|
|
||||||
TimerHandle_t mqttReconnectTimer;
|
|
||||||
IPAddress ip;
|
|
||||||
uint16_t port;
|
|
||||||
const char *username;
|
|
||||||
const char *password;
|
|
||||||
const char *prefix;
|
|
||||||
|
|
||||||
void init(const char *host, uint16_t port, const char *id, const char *username, const char *password, const char *prefix);
|
|
||||||
void publishPacket(SondeInfo *s);
|
|
||||||
void publishUptime();
|
|
||||||
private:
|
|
||||||
void connectToMqtt();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_RS92
|
||||||
|
|
||||||
/* SPDX-License-Identifier: GPL-3.0
|
/* SPDX-License-Identifier: GPL-3.0
|
||||||
* based on https://github.com/rs1729/RS/blob/master/rs92/nav_gps_vel.c
|
* based on https://github.com/rs1729/RS/blob/master/rs92/nav_gps_vel.c
|
||||||
*
|
*
|
||||||
|
@ -1713,3 +1716,4 @@ int NAV_LinV(int N, SAT_t satv[], double pos_ecef[3],
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,545 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "pmu.h"
|
||||||
|
#include "Sonde.h"
|
||||||
|
|
||||||
|
// 0: cleared; 1: set; 2: do not check, also query state of axp via i2c on each loop
|
||||||
|
uint8_t pmu_irq = 0;
|
||||||
|
#define PMU_IRQ 35
|
||||||
|
|
||||||
|
#define AXP192_VMIN 1800
|
||||||
|
#define AXP192_VSTEP 100
|
||||||
|
|
||||||
|
|
||||||
|
#define AXP192_IC_TYPE (0x03)
|
||||||
|
|
||||||
|
#define AXP192_DC_MIN 700
|
||||||
|
#define AXP192_DC_STEPS 25
|
||||||
|
|
||||||
|
#define AXP192_LDO_MIN (1800)
|
||||||
|
#define AXP192_LDO_STEPS (100)
|
||||||
|
|
||||||
|
#define AXP192_VOLTREG_DC1
|
||||||
|
|
||||||
|
// some registers:
|
||||||
|
#define AXP192_STATUS (0x00)
|
||||||
|
#define AXP192_MODE_CHGSTATUS (0x01)
|
||||||
|
|
||||||
|
// Power voltage control register
|
||||||
|
#define AXP192_DC2OUT_VOL (0x23)
|
||||||
|
#define AXP192_DC1OUT_VOL (0x26)
|
||||||
|
#define AXP192_DC3OUT_VOL (0x27)
|
||||||
|
#define AXP192_LDO23OUT_VOL (0x28)
|
||||||
|
#define AXP192_GPIO0_VOL (0x91)
|
||||||
|
|
||||||
|
// Power enable registers
|
||||||
|
#define AXP192_LDO23_DC123_EXT_CTL (0x12)
|
||||||
|
|
||||||
|
// ADC control
|
||||||
|
#define AXP192_ADC_EN1 (0x82)
|
||||||
|
|
||||||
|
// ADC results
|
||||||
|
#define AXP192_BAT_AVERVOL_H8 (0x78)
|
||||||
|
#define AXP192_BAT_AVERVOL_L4 (0x79)
|
||||||
|
#define AXP192_BAT_AVERCHGCUR_H8 (0x7A)
|
||||||
|
#define AXP192_BAT_AVERCHGCUR_L4 (0x7B)
|
||||||
|
#define AXP192_BAT_AVERCHGCUR_L5 (0x7B)
|
||||||
|
#define AXP192_ACIN_VOL_H8 (0x56)
|
||||||
|
#define AXP192_ACIN_VOL_L4 (0x57)
|
||||||
|
#define AXP192_ACIN_CUR_H8 (0x58)
|
||||||
|
#define AXP192_ACIN_CUR_L4 (0x59)
|
||||||
|
#define AXP192_VBUS_VOL_H8 (0x5A)
|
||||||
|
#define AXP192_VBUS_VOL_L4 (0x5B)
|
||||||
|
#define AXP192_VBUS_CUR_H8 (0x5C)
|
||||||
|
#define AXP192_VBUS_CUR_L4 (0x5D)
|
||||||
|
#define AXP192_INTERNAL_TEMP_H8 (0x5E)
|
||||||
|
#define AXP192_INTERNAL_TEMP_L4 (0x5F)
|
||||||
|
#define AXP192_TS_IN_H8 (0x62)
|
||||||
|
#define AXP192_TS_IN_L4 (0x63)
|
||||||
|
#define AXP192_GPIO0_VOL_ADC_H8 (0x64)
|
||||||
|
#define AXP192_GPIO0_VOL_ADC_L4 (0x65)
|
||||||
|
#define AXP192_GPIO1_VOL_ADC_H8 (0x66)
|
||||||
|
#define AXP192_GPIO1_VOL_ADC_L4 (0x67)
|
||||||
|
#define AXP192_BAT_AVERDISCHGCUR_H8 (0x7C)
|
||||||
|
#define AXP192_BAT_AVERDISCHGCUR_L5 (0x7D)
|
||||||
|
|
||||||
|
|
||||||
|
// Interrupt enable
|
||||||
|
#define AXP192_INTEN1 (0x40)
|
||||||
|
#define AXP192_INTEN2 (0x41)
|
||||||
|
#define AXP192_INTEN3 (0x42)
|
||||||
|
#define AXP192_INTEN4 (0x43)
|
||||||
|
#define AXP192_INTEN5 (0x4A)
|
||||||
|
|
||||||
|
// Int clear.
|
||||||
|
#define AXP192_INTSTS1 (0x44)
|
||||||
|
#define AXP192_INTSTS2 (0x45)
|
||||||
|
#define AXP192_INTSTS3 (0x46)
|
||||||
|
#define AXP192_INTSTS4 (0x47)
|
||||||
|
#define AXP192_INTSTS5 (0x4D)
|
||||||
|
|
||||||
|
extern SemaphoreHandle_t axpSemaphore;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// High-level functions
|
||||||
|
PMU *PMU::getInstance(TwoWire &wire) {
|
||||||
|
PMU *pmu = NULL;
|
||||||
|
// Check if there is some AXP192 or AXP2101 present
|
||||||
|
uint8_t chipid = readRegisterWire(wire, AXP192_IC_TYPE);
|
||||||
|
// AXP192: 0x03 AXP2101: 0x4A
|
||||||
|
if(chipid==0x03) {
|
||||||
|
pmu = new AXP192PMU(wire);
|
||||||
|
}
|
||||||
|
else if (chipid==0x4A) {
|
||||||
|
pmu = new AXP2101PMU(wire);
|
||||||
|
}
|
||||||
|
return pmu;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PMU::readRegisterWire(TwoWire &wire, uint8_t reg) {
|
||||||
|
wire.beginTransmission(AXP192_SLAVE_ADDRESS);
|
||||||
|
wire.write(reg);
|
||||||
|
if (wire.endTransmission() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wire.requestFrom(AXP192_SLAVE_ADDRESS, 1U);
|
||||||
|
return wire.read();
|
||||||
|
}
|
||||||
|
int PMU::readRegister(uint8_t reg) {
|
||||||
|
return readRegisterWire(_wire, reg);
|
||||||
|
}
|
||||||
|
uint16_t PMU::readRegisters_8_4(uint8_t regh, uint8_t regl)
|
||||||
|
{
|
||||||
|
uint8_t hi = readRegister(regh);
|
||||||
|
uint8_t lo = readRegister(regl);
|
||||||
|
return (hi << 4) | (lo & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t PMU::readRegisters_8_5(uint8_t regh, uint8_t regl)
|
||||||
|
{
|
||||||
|
uint8_t hi = readRegister(regh);
|
||||||
|
uint8_t lo = readRegister(regl);
|
||||||
|
return (hi << 5) | (lo & 0x1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PMU::writeRegister(uint8_t reg, uint8_t val) {
|
||||||
|
_wire.beginTransmission(AXP192_SLAVE_ADDRESS);
|
||||||
|
_wire.write(reg);
|
||||||
|
_wire.write(val);
|
||||||
|
return (_wire.endTransmission() == 0) ? 0 : -1;
|
||||||
|
}
|
||||||
|
int PMU::getRegisterBit(uint8_t reg, uint8_t bit) {
|
||||||
|
int val = readRegister(reg);
|
||||||
|
if (val == -1) { return -1; }
|
||||||
|
return (val >> bit) & 0x01;
|
||||||
|
}
|
||||||
|
int PMU::setRegisterBit(uint8_t reg, uint8_t bit) {
|
||||||
|
int val = readRegister(reg);
|
||||||
|
if (val == -1) { return -1; }
|
||||||
|
return writeRegister(reg, (val | (1<<bit)));
|
||||||
|
}
|
||||||
|
int PMU::clearRegisterBit(uint8_t reg, uint8_t bit) {
|
||||||
|
int val = readRegister(reg);
|
||||||
|
if (val == -1) { return -1; }
|
||||||
|
return writeRegister(reg, (val & ( ~(1<<bit))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns if there was a keypress, using the following enum defined in RX_FSK.ini:
|
||||||
|
enum KeyPress { KP_NONE = 0, KP_SHORT, KP_DOUBLE, KP_MID, KP_LONG };
|
||||||
|
|
||||||
|
int PMU::handleIRQ() {
|
||||||
|
if (pmu_irq) {
|
||||||
|
Serial.println("PMU_IRQ is set\n");
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int keypress = -1;
|
||||||
|
xSemaphoreTake( axpSemaphore, portMAX_DELAY );
|
||||||
|
keypress = getIrqKeyStatus();
|
||||||
|
if(keypress) { Serial.printf("Keypress: %d (%s)", keypress, keypress==KP_SHORT?"short":"mid"); }
|
||||||
|
if (pmu_irq != 2) {
|
||||||
|
pmu_irq = 0;
|
||||||
|
}
|
||||||
|
xSemaphoreGive( axpSemaphore );
|
||||||
|
return keypress;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP192PMU::init() {
|
||||||
|
// Initialize AXP192, for T-BEAM v1.1 or M5Stack
|
||||||
|
|
||||||
|
// LDO2: LoRa VCC on T-BEAM, PERI_VDD on M5Core2 (LCD)
|
||||||
|
setLDO2(3300);
|
||||||
|
enableLDO2();
|
||||||
|
if(sonde.config.type == TYPE_M5_CORE2) {
|
||||||
|
// Display backlight (LCD_BL) on M5 Core2
|
||||||
|
setDC3(3300);
|
||||||
|
enableDC3();
|
||||||
|
pmu_irq = 2; // IRQ pin not connected on Core2
|
||||||
|
// Set GPIO0 VDO to 3.3V (as is done by original M5Stack software)
|
||||||
|
// (default value 2.8V did not have the expected effect :))
|
||||||
|
setLDOio(3300);
|
||||||
|
// ADC configuration: Enable monitoring of AC [bits 4,5 in enable register]
|
||||||
|
uint8_t val = readRegister(AXP192_ADC_EN1);
|
||||||
|
writeRegister(AXP192_ADC_EN1, val | (1 << 4) | (1 << 5) );
|
||||||
|
} else {
|
||||||
|
// T-Beam specific
|
||||||
|
// GPS power on T-Beam (its the buzzer on M5 Core2, so only enable for T-Beam)
|
||||||
|
enableLDO3();
|
||||||
|
// ADC configuration: Enable monitoring of USB [bits 2,3 in enable register]
|
||||||
|
uint8_t val = readRegister(AXP192_ADC_EN1);
|
||||||
|
writeRegister(AXP192_ADC_EN1, val | (1 << 4) | (1 << 5) );
|
||||||
|
}
|
||||||
|
// Common configuration for T-Beam and M5 Core2
|
||||||
|
// DCDC2: M5Core: Unused, T-Beam: Unused, so set to disabled!! (was enabled in previous versions)
|
||||||
|
enableDC2(false);
|
||||||
|
|
||||||
|
// EXTEN: M5Core2: 5V Boost enable; T-Beam EXTEN
|
||||||
|
enableEXTEN();
|
||||||
|
|
||||||
|
// DCDC1: M5Core: MCU_VDD, T-Beam 1.1: "VCC_2.5V" == 3V3-Pin on pin header on board
|
||||||
|
setDC1(3300);
|
||||||
|
enableDC1();
|
||||||
|
|
||||||
|
// ADC configuration: Enable monitor batt current [bit 6 in eable register]
|
||||||
|
uint8_t val = readRegister(AXP192_ADC_EN1);
|
||||||
|
writeRegister(AXP192_ADC_EN1, val | (1 << 6) );
|
||||||
|
|
||||||
|
if (pmu_irq != 2) {
|
||||||
|
pinMode(PMU_IRQ, INPUT_PULLUP);
|
||||||
|
attachInterrupt(PMU_IRQ, [] {
|
||||||
|
pmu_irq = 1;
|
||||||
|
}, FALLING);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// Helper functions
|
||||||
|
|
||||||
|
int AXP192PMU::getIrqKeyStatus() {
|
||||||
|
int status = readRegister(AXP192_INTSTS3);
|
||||||
|
|
||||||
|
// Also clear IRQ status
|
||||||
|
writeRegister(AXP192_INTSTS1, 0xFF);
|
||||||
|
writeRegister(AXP192_INTSTS2, 0xFF);
|
||||||
|
writeRegister(AXP192_INTSTS3, 0xFF);
|
||||||
|
writeRegister(AXP192_INTSTS4, 0xFF);
|
||||||
|
writeRegister(AXP192_INTSTS5, 0xFF);
|
||||||
|
|
||||||
|
//
|
||||||
|
if ( status & 0x01 ) return KP_MID;
|
||||||
|
if ( status & 0x02 ) return KP_SHORT;
|
||||||
|
return KP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AXP192PMU::disableAllIRQ() {
|
||||||
|
writeRegister(AXP192_INTEN1, 0);
|
||||||
|
writeRegister(AXP192_INTEN2, 0);
|
||||||
|
writeRegister(AXP192_INTEN3, 0);
|
||||||
|
writeRegister(AXP192_INTEN4, 0);
|
||||||
|
writeRegister(AXP192_INTEN5, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AXP192PMU::_enableIRQ(uint8_t addr, uint8_t mask) {
|
||||||
|
int data = readRegister(addr);
|
||||||
|
writeRegister(addr, data | mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we want KP_SHORT and KP_LONG interrupts...
|
||||||
|
// IRQ4, in reg 0x42h, Bit 16+17
|
||||||
|
void AXP192PMU::enableIRQ() {
|
||||||
|
//_enableIRQ( AXP192_INTEN1, mask&0xFF );
|
||||||
|
//_enableIRQ( AXP192_INTEN2, mask>>8 );
|
||||||
|
_enableIRQ( AXP192_INTEN3, 0x03 );
|
||||||
|
//_enableIRQ( AXP192_INTEN4, mask>>24 );
|
||||||
|
//_enableIRQ( AXP192_INTEN5, mask>>32 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions for setting voltage output levels
|
||||||
|
int AXP192PMU::setVoltageReg(uint8_t reg, uint8_t regval) {
|
||||||
|
int val = readRegister(reg);
|
||||||
|
if (val==-1) return -1;
|
||||||
|
val &= 0x80;
|
||||||
|
val |= regval;
|
||||||
|
return writeRegister(reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP192PMU::setDC1(uint16_t millivolt) {
|
||||||
|
return setVoltageReg(AXP192_DC1OUT_VOL, (millivolt-AXP192_DC_MIN)/AXP192_DC_STEPS );
|
||||||
|
}
|
||||||
|
int AXP192PMU::setDC2(uint16_t millivolt) {
|
||||||
|
return setVoltageReg(AXP192_DC2OUT_VOL, (millivolt-AXP192_DC_MIN)/AXP192_DC_STEPS );
|
||||||
|
}
|
||||||
|
int AXP192PMU::setDC3(uint16_t millivolt) {
|
||||||
|
return setVoltageReg(AXP192_DC3OUT_VOL , (millivolt-AXP192_DC_MIN)/AXP192_DC_STEPS );
|
||||||
|
}
|
||||||
|
int AXP192PMU::setLDO2(uint16_t millivolt) {
|
||||||
|
return setVoltageReg(AXP192_LDO23OUT_VOL, (millivolt-AXP192_LDO_MIN)/AXP192_LDO_STEPS);
|
||||||
|
}
|
||||||
|
int AXP192PMU::setLDOio(uint16_t millivolt) {
|
||||||
|
return setVoltageReg(AXP192_GPIO0_VOL, (millivolt-AXP192_LDO_MIN)/AXP192_LDO_STEPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// LDO23_DC123_EXT_CTL
|
||||||
|
// 0:DC-DC1, 1:DC-DC3, 2:LDO2, 3:LDO3, 4:DC-DC2, 6:EXTEN
|
||||||
|
int AXP192PMU::enableDC1(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 0) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 0);
|
||||||
|
}
|
||||||
|
int AXP192PMU::enableDC3(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 1) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 1);
|
||||||
|
}
|
||||||
|
int AXP192PMU::enableLDO2(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 2) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 2);
|
||||||
|
}
|
||||||
|
int AXP192PMU::enableLDO3(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 3) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 3);
|
||||||
|
}
|
||||||
|
int AXP192PMU::enableDC2(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 4) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 4);
|
||||||
|
}
|
||||||
|
int AXP192PMU::enableEXTEN(bool onoff) {
|
||||||
|
return onoff ? setRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 6) : clearRegisterBit(AXP192_LDO23_DC123_EXT_CTL, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP192PMU::enableADC(uint8_t channels) {
|
||||||
|
uint8_t val = readRegister(AXP192_ADC_EN1);
|
||||||
|
return writeRegister(AXP192_ADC_EN1, val | channels );
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP192PMU::isBatteryConnected() {
|
||||||
|
return getRegisterBit(AXP192_MODE_CHGSTATUS, 5);
|
||||||
|
}
|
||||||
|
int AXP192PMU::isVbusIn() {
|
||||||
|
return getRegisterBit(AXP192_STATUS, 5);
|
||||||
|
}
|
||||||
|
int AXP192PMU::isCharging() {
|
||||||
|
return getRegisterBit(AXP192_MODE_CHGSTATUS, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_BATT_VOLTAGE_STEP (1.1F)
|
||||||
|
float AXP192PMU::getBattVoltage() {
|
||||||
|
return readRegisters_8_4(AXP192_BAT_AVERVOL_H8, AXP192_BAT_AVERVOL_L4) * AXP192_BATT_VOLTAGE_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_BATT_DISCHARGE_CUR_STEP (0.5F)
|
||||||
|
float AXP192PMU::getBattDischargeCurrent() {
|
||||||
|
return readRegisters_8_5(AXP192_BAT_AVERDISCHGCUR_H8, AXP192_BAT_AVERDISCHGCUR_L5) * AXP192_BATT_DISCHARGE_CUR_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_BATT_CHARGE_CUR_STEP (0.5F)
|
||||||
|
float AXP192PMU::getBattChargeCurrent() {
|
||||||
|
return readRegisters_8_5(AXP192_BAT_AVERCHGCUR_H8, AXP192_BAT_AVERCHGCUR_L5) * AXP192_BATT_CHARGE_CUR_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_ACIN_VOLTAGE_STEP (1.7F)
|
||||||
|
float AXP192PMU::getAcinVoltage() {
|
||||||
|
return readRegisters_8_4(AXP192_ACIN_VOL_H8, AXP192_ACIN_VOL_L4) * AXP192_ACIN_VOLTAGE_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_ACIN_CUR_STEP (0.625F)
|
||||||
|
float AXP192PMU::getAcinCurrent() {
|
||||||
|
return readRegisters_8_4(AXP192_ACIN_CUR_H8, AXP192_ACIN_CUR_L4) * AXP192_ACIN_CUR_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_VBUS_VOLTAGE_STEP (1.7F)
|
||||||
|
float AXP192PMU::getVbusVoltage() {
|
||||||
|
return readRegisters_8_4(AXP192_VBUS_VOL_H8, AXP192_VBUS_VOL_L4) * AXP192_VBUS_VOLTAGE_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_VBUS_CUR_STEP (0.375F)
|
||||||
|
float AXP192PMU::getVbusCurrent() {
|
||||||
|
return readRegisters_8_4(AXP192_VBUS_CUR_H8, AXP192_VBUS_CUR_L4) * AXP192_VBUS_CUR_STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AXP192_INTERNAL_TEMP_STEP (0.1F)
|
||||||
|
float AXP192PMU::getTemperature() {
|
||||||
|
return readRegisters_8_4(AXP192_INTERNAL_TEMP_H8, AXP192_INTERNAL_TEMP_L4) * AXP192_INTERNAL_TEMP_STEP - 144.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/////// Functions for AXP2101
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
#define AXP2101_CHARGE_GAUGE_WDT_CTRL (0x18)
|
||||||
|
#define AXP2101_BTN_BAT_CHG_VOL_SET (0x6A)
|
||||||
|
#define AXP2101_DC_ONOFF_DVM_CTRL (0x80)
|
||||||
|
#define AXP2101_LDO_ONOFF_CTRL0 (0x90)
|
||||||
|
#define AXP2101_LDO_ONOFF_CTRL1 (0x91)
|
||||||
|
|
||||||
|
#define AXP2101_LDO_VOL1_CTRL (0x93)
|
||||||
|
#define AXP2101_LDO_VOL2_CTRL (0x94)
|
||||||
|
|
||||||
|
#define AXP2101_ADC_CHANNEL_CTRL (0x30)
|
||||||
|
|
||||||
|
// vterm_cfg: Bit 2:0, 4.2V = 011 (3)
|
||||||
|
#define AXP2101_CHG_V_CFG (0x64)
|
||||||
|
// ICC_CFG: Bit 4:0: constant current charge current limit, 25*N mA (N<=8), 200+100*(N-8) (N>8)
|
||||||
|
#define AXP2101_ICC_CFG (0x62)
|
||||||
|
|
||||||
|
// Interrupt enable
|
||||||
|
#define AXP2101_INTEN1 (0x40)
|
||||||
|
#define AXP2101_INTEN2 (0x41)
|
||||||
|
#define AXP2101_INTEN3 (0x42)
|
||||||
|
|
||||||
|
// Interrupt status
|
||||||
|
#define AXP2101_INTSTS1 (0x48)
|
||||||
|
#define AXP2101_INTSTS2 (0x49)
|
||||||
|
#define AXP2101_INTSTS3 (0x4A)
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
#define AXP2101_ALDO_VOL_MIN (500)
|
||||||
|
#define AXP2101_ALDO_VOL_STEPS (100)
|
||||||
|
|
||||||
|
#define AXP2101_BTN_VOL_MIN (2600)
|
||||||
|
#define AXP2101_BTN_VOL_STEPS (100)
|
||||||
|
|
||||||
|
// 200 + 100*(11-8) = 500
|
||||||
|
#define AXP2101_CHG_CUR_500MA (0x0B)
|
||||||
|
#define AXP2101_CHG_VOL_4V2 (3)
|
||||||
|
|
||||||
|
|
||||||
|
// return 0: ok, -1: error
|
||||||
|
int AXP2101PMU::init() {
|
||||||
|
// Initialize AXP2101, for T-BEAM v1.2
|
||||||
|
|
||||||
|
// Hard-coded for now, disable DC2/3/4/5 ALDO1,4 BLDO1/2 DLDO1/2
|
||||||
|
int val = readRegister(AXP2101_DC_ONOFF_DVM_CTRL);
|
||||||
|
writeRegister(AXP2101_DC_ONOFF_DVM_CTRL, val & (~0x1E)); // clear Bit 1,2,3,4 (DC2/3/4/5)
|
||||||
|
|
||||||
|
// clear bit 0 (aldo1), 3 (aldo4), 4,5(bldo1/2), 7 (dldo1)
|
||||||
|
val = readRegister(AXP2101_LDO_ONOFF_CTRL0);
|
||||||
|
writeRegister(AXP2101_LDO_ONOFF_CTRL0, val & (~0xB9));
|
||||||
|
|
||||||
|
// clear bit 0 (dldo2)
|
||||||
|
val = readRegister(AXP2101_LDO_ONOFF_CTRL1);
|
||||||
|
writeRegister(AXP2101_LDO_ONOFF_CTRL1, val & (~0x01));
|
||||||
|
|
||||||
|
// Set PowerVDD to 3100mV (GNSS RTC) -- reg 6A [MS412FE data sheet: charge volt 2.8-3.3; standard value 3.1]
|
||||||
|
val = readRegister(AXP2101_BTN_BAT_CHG_VOL_SET);
|
||||||
|
if (val == -1) return -1;
|
||||||
|
val &= 0xF8;
|
||||||
|
val |= (3100 - AXP2101_BTN_VOL_MIN) / AXP2101_BTN_VOL_STEPS;
|
||||||
|
writeRegister(AXP2101_BTN_BAT_CHG_VOL_SET, val);
|
||||||
|
|
||||||
|
setRegisterBit(AXP2101_CHARGE_GAUGE_WDT_CTRL, 2);
|
||||||
|
|
||||||
|
// ESP32 VDD 3300mV
|
||||||
|
// No need to set, automatically open , Don't close it
|
||||||
|
|
||||||
|
// LoRa VDD 3300mV on ALDO2
|
||||||
|
val = readRegister(AXP2101_LDO_VOL1_CTRL);
|
||||||
|
if (val == -1) return -1;
|
||||||
|
val &= 0xE0;
|
||||||
|
val |= (3300 - AXP2101_ALDO_VOL_MIN) / AXP2101_ALDO_VOL_STEPS;
|
||||||
|
writeRegister(AXP2101_LDO_VOL1_CTRL, val);
|
||||||
|
setRegisterBit(AXP2101_LDO_ONOFF_CTRL0, 1);
|
||||||
|
|
||||||
|
// GNSS VDD 3300mV on ALDO3
|
||||||
|
val = readRegister(AXP2101_LDO_VOL2_CTRL);
|
||||||
|
if (val == -1) return -1;
|
||||||
|
val &= 0xE0;
|
||||||
|
val |= (3300 - AXP2101_ALDO_VOL_MIN) / AXP2101_ALDO_VOL_STEPS;
|
||||||
|
writeRegister(AXP2101_LDO_VOL2_CTRL, val);
|
||||||
|
setRegisterBit(AXP2101_LDO_ONOFF_CTRL0, 2);
|
||||||
|
|
||||||
|
if (pmu_irq != 2) {
|
||||||
|
pinMode(PMU_IRQ, INPUT_PULLUP);
|
||||||
|
attachInterrupt(PMU_IRQ, [] {
|
||||||
|
pmu_irq = 1;
|
||||||
|
}, FALLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set charging configuration: 500mA, 4.2V cut off
|
||||||
|
|
||||||
|
// Set constant current charge limit to 500mA (reguster 0x62)
|
||||||
|
// Data sheep (7.3.3.) tells that default value is 1.024 A (which should be fine??)
|
||||||
|
// Data sheet (register table) tells that default value is "{EFUSE,0b,EFUSE}", whatever that is
|
||||||
|
// Let's set this to 500 mA manually to be sure
|
||||||
|
val = readRegister(AXP2101_ICC_CFG);
|
||||||
|
if (val == -1) return -1;
|
||||||
|
val &= 0xE0;
|
||||||
|
writeRegister(AXP2101_ICC_CFG, val | AXP2101_CHG_CUR_500MA);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Set cut-off voltage to 4.2V (register 0x63)
|
||||||
|
// This is the default value, so setting it should not be needed.
|
||||||
|
val = readRegister(AXP2101_CHG_V_CFG);
|
||||||
|
if (val == -1) return -1;
|
||||||
|
val &= 0xFC;
|
||||||
|
writeRegister(AXP2101_CHG_V_CFG, val | AXP2101_CHG_VOL_4V2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Disable TS measurement, enable vsys, vbus, vbat measurement
|
||||||
|
// Disable TS is important for T-Beam 1.2 (no TS thermistor), otherwise it will not charge.
|
||||||
|
writeRegister(AXP2101_ADC_CHANNEL_CTRL, 0x0d);
|
||||||
|
|
||||||
|
// Clear all IRQ
|
||||||
|
getIrqKeyStatus();
|
||||||
|
|
||||||
|
// precharge current (reg 0x61): default value (0101b) should be fine
|
||||||
|
// Termination current (125mA default value) should be fine as well
|
||||||
|
#if 0
|
||||||
|
// Just some debug code
|
||||||
|
Serial.println("All good \n");
|
||||||
|
|
||||||
|
for(int i=0; i<0x80; i++) {
|
||||||
|
val = readRegister(i);
|
||||||
|
Serial.printf("Reg %x: %x (%d)\n", i, val, val);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AXP2101PMU::disableAllIRQ() {
|
||||||
|
writeRegister(AXP2101_INTEN1, 0);
|
||||||
|
writeRegister(AXP2101_INTEN2, 0);
|
||||||
|
writeRegister(AXP2101_INTEN3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AXP2101PMU::_enableIRQ(uint8_t addr, uint8_t mask) {
|
||||||
|
int data = readRegister(addr);
|
||||||
|
writeRegister(addr, data | mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we want KP_SHORT and KP_LONG interrupts...
|
||||||
|
// IRQen1, in req 0x41h, Bit 2(long)+3(short) (10+11 global)
|
||||||
|
void AXP2101PMU::enableIRQ() {
|
||||||
|
//_enableIRQ( AXP2101_INTEN1, mask&0xFF );
|
||||||
|
_enableIRQ( AXP2101_INTEN2, 0x0C );
|
||||||
|
//_enableIRQ( AXP2101_INTEN3, 0x03 );
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP2101PMU::getIrqKeyStatus() {
|
||||||
|
int status = readRegister(AXP2101_INTSTS2);
|
||||||
|
|
||||||
|
// Also clear IRQ status
|
||||||
|
writeRegister(AXP2101_INTSTS1, 0xFF);
|
||||||
|
writeRegister(AXP2101_INTSTS2, 0xFF);
|
||||||
|
writeRegister(AXP2101_INTSTS3, 0xFF);
|
||||||
|
|
||||||
|
//
|
||||||
|
if ( status & 0x04 ) return KP_MID;
|
||||||
|
if ( status & 0x08 ) return KP_SHORT;
|
||||||
|
return KP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AXP2101PMU::isBatteryConnected() { return -1; }
|
||||||
|
int AXP2101PMU::isVbusIn() { return -1; }
|
||||||
|
int AXP2101PMU::isCharging() { return -1; }
|
||||||
|
float AXP2101PMU::getBattVoltage() { return -1; }
|
||||||
|
float AXP2101PMU::getBattDischargeCurrent() { return -1; }
|
||||||
|
float AXP2101PMU::getBattChargeCurrent() { return -1; }
|
||||||
|
float AXP2101PMU::getAcinVoltage() { return -1; }
|
||||||
|
float AXP2101PMU::getAcinCurrent() { return -1; }
|
||||||
|
float AXP2101PMU::getVbusVoltage() { return -1; }
|
||||||
|
float AXP2101PMU::getVbusCurrent() { return -1; }
|
||||||
|
float AXP2101PMU::getTemperature() { return -1; }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#define AXP192_SLAVE_ADDRESS 0x34
|
||||||
|
|
||||||
|
enum { TYPE_NONE=-1, TYPE_UNKNOWN=0, TYPE_AXP192, TYPE_AXP2101 };
|
||||||
|
|
||||||
|
class PMU {
|
||||||
|
protected:
|
||||||
|
PMU(TwoWire &wire) : _wire(wire) { };
|
||||||
|
|
||||||
|
public:
|
||||||
|
TwoWire &_wire;
|
||||||
|
static PMU *getInstance(TwoWire &wire);
|
||||||
|
int type;
|
||||||
|
|
||||||
|
static int readRegisterWire(TwoWire &wire, uint8_t reg);
|
||||||
|
int readRegister(uint8_t reg);
|
||||||
|
uint16_t readRegisters_8_4(uint8_t reghi, uint8_t reglo);
|
||||||
|
uint16_t readRegisters_8_5(uint8_t reghi, uint8_t reglo);
|
||||||
|
int writeRegister(uint8_t reg, uint8_t val);
|
||||||
|
int getRegisterBit(uint8_t register, uint8_t bit);
|
||||||
|
int setRegisterBit(uint8_t register, uint8_t bit);
|
||||||
|
int clearRegisterBit(uint8_t register, uint8_t bit);
|
||||||
|
|
||||||
|
int handleIRQ();
|
||||||
|
|
||||||
|
virtual int init();
|
||||||
|
virtual void disableAllIRQ();
|
||||||
|
virtual void enableIRQ();
|
||||||
|
virtual int getIrqKeyStatus();
|
||||||
|
|
||||||
|
virtual int isBatteryConnected();
|
||||||
|
virtual int isVbusIn();
|
||||||
|
virtual int isCharging();
|
||||||
|
virtual float getBattVoltage();
|
||||||
|
virtual float getBattDischargeCurrent();
|
||||||
|
virtual float getBattChargeCurrent();
|
||||||
|
virtual float getAcinVoltage();
|
||||||
|
virtual float getAcinCurrent();
|
||||||
|
virtual float getVbusVoltage();
|
||||||
|
virtual float getVbusCurrent();
|
||||||
|
virtual float getTemperature();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Interface */
|
||||||
|
class AXP192PMU : public PMU {
|
||||||
|
public:
|
||||||
|
AXP192PMU(TwoWire &wire) : PMU(wire) { type = TYPE_AXP192; };
|
||||||
|
int init();
|
||||||
|
void disableAllIRQ();
|
||||||
|
void enableIRQ();
|
||||||
|
int getIrqKeyStatus();
|
||||||
|
|
||||||
|
int isBatteryConnected();
|
||||||
|
int isVbusIn();
|
||||||
|
int isCharging();
|
||||||
|
float getBattVoltage();
|
||||||
|
float getBattDischargeCurrent();
|
||||||
|
float getBattChargeCurrent();
|
||||||
|
float getAcinVoltage();
|
||||||
|
float getAcinCurrent();
|
||||||
|
float getVbusVoltage();
|
||||||
|
float getVbusCurrent();
|
||||||
|
float getTemperature();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _enableIRQ(uint8_t addr, uint8_t mask);
|
||||||
|
|
||||||
|
int setVoltageReg(uint8_t reg, uint8_t regval);
|
||||||
|
int setDC1(uint16_t millivolt);
|
||||||
|
int setDC2(uint16_t millivolt);
|
||||||
|
int setDC3(uint16_t millivolt);
|
||||||
|
int setLDO2(uint16_t millivolt);
|
||||||
|
int setLDOio(uint16_t millivolt);
|
||||||
|
|
||||||
|
int enableDC1(bool onff = true);
|
||||||
|
int enableDC3(bool onoff = true);
|
||||||
|
int enableLDO2(bool onoff = true);
|
||||||
|
int enableLDO3(bool onoff = true);
|
||||||
|
int enableDC2(bool onoff = true);
|
||||||
|
int enableEXTEN(bool onoff = true);
|
||||||
|
|
||||||
|
int enableADC(uint8_t channels);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AXP2101PMU : public PMU {
|
||||||
|
public:
|
||||||
|
AXP2101PMU(TwoWire &wire) : PMU(wire) { };
|
||||||
|
int init();
|
||||||
|
void disableAllIRQ();
|
||||||
|
void enableIRQ();
|
||||||
|
int getIrqKeyStatus();
|
||||||
|
|
||||||
|
int isBatteryConnected();
|
||||||
|
int isVbusIn();
|
||||||
|
int isCharging();
|
||||||
|
float getBattVoltage();
|
||||||
|
float getBattDischargeCurrent();
|
||||||
|
float getBattChargeCurrent();
|
||||||
|
float getAcinVoltage();
|
||||||
|
float getAcinCurrent();
|
||||||
|
float getVbusVoltage();
|
||||||
|
float getVbusCurrent();
|
||||||
|
float getTemperature();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _enableIRQ(uint8_t addr, uint8_t mask);
|
||||||
|
|
||||||
|
int setVBACKUP(uint16_t millivolt);
|
||||||
|
int setDCDC1(uint16_t millivolt);
|
||||||
|
int setALDO2(uint16_t millivolt);
|
||||||
|
int setALDO3(uint16_t millivolt);
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,271 @@
|
||||||
|
#include "posinfo.h"
|
||||||
|
|
||||||
|
#include <MicroNMEA.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Sation position obtained from GPS (if available)
|
||||||
|
struct StationPos gpsPos;
|
||||||
|
|
||||||
|
// Station position to use (from GPS or fixed)
|
||||||
|
struct StationPos posInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/* SH_LOC_OFF: never send position information to SondeHub
|
||||||
|
SH_LOC_FIXED: send fixed position (if specified in config) to sondehub
|
||||||
|
SH_LOC_CHASE: always activate chase mode and send GPS position (if available)
|
||||||
|
SH_LOC_AUTO: if there is no valid GPS position, or GPS position < MIN_LOC_AUTO_DIST away from known fixed position: use FIXED mode
|
||||||
|
otherwise, i.e. if there is a valid GPS position and (either no fixed position in config, or GPS position is far away from fixed position), use CHASE mode.
|
||||||
|
*/
|
||||||
|
// same constants used for SondeHub and APRS
|
||||||
|
|
||||||
|
/* auto mode is chase if valid GPS position and (no fixed location entered OR valid GPS position and distance in lat/lon deg to fixed location > threshold) */
|
||||||
|
//#define MIN_LOC_AUTO_DIST 200 /* meter */
|
||||||
|
//#define SH_LOC_AUTO_IS_CHASE ( gpsPos.valid && ( (isnan(sonde.config.rxlat) || isnan(sonde.config.rxlon) ) || \
|
||||||
|
// calcLatLonDist( gpsPos.lat, gpsPos.lon, sonde.config.rxlat, sonde.config.rxlon ) > MIN_LOC_AUTO_DIST ) )
|
||||||
|
//extern float calcLatLonDist(float lat1, float lon1, float lat2, float lon2);
|
||||||
|
|
||||||
|
/////
|
||||||
|
// set fixed position based on config
|
||||||
|
void fixedToPosInfo() {
|
||||||
|
memset(&posInfo, 0, sizeof(posInfo));
|
||||||
|
if( isnan(sonde.config.rxlat) || isnan(sonde.config.rxlon) )
|
||||||
|
return;
|
||||||
|
posInfo.lat = sonde.config.rxlat;
|
||||||
|
posInfo.lon = sonde.config.rxlon;
|
||||||
|
posInfo.alt = sonde.config.rxalt;
|
||||||
|
posInfo.valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///// GPS handling functions
|
||||||
|
|
||||||
|
static char buffer[85];
|
||||||
|
static MicroNMEA nmea(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
|
||||||
|
/// Arrg. MicroNMEA changes type definition... so lets auto-infer type
|
||||||
|
template<typename T>
|
||||||
|
//void unkHandler(const MicroNMEA& nmea) {
|
||||||
|
void unkHandler(T nmea) {
|
||||||
|
if (strcmp(nmea.getMessageID(), "VTG") == 0) {
|
||||||
|
const char *s = nmea.getSentence();
|
||||||
|
while (*s && *s != ',') s++;
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
if (*s == ',') return; /// no new course data
|
||||||
|
int lastCourse = nmea.parseFloat(s, 0, NULL);
|
||||||
|
Serial.printf("Course update: %d\n", lastCourse);
|
||||||
|
} else if (strcmp(nmea.getMessageID(), "GST") == 0) {
|
||||||
|
// get horizontal accuracy for android app on devices without gps
|
||||||
|
// GPGST,time,rms,-,-,-,stdlat,stdlon,stdalt,cs
|
||||||
|
const char *s = nmea.getSentence();
|
||||||
|
while (*s && *s != ',') s++; // #0: GST
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
while (*s && *s != ',') s++; // #1: time: skip
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
while (*s && *s != ',') s++; // #1: rms: skip
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
while (*s && *s != ',') s++; // #1: (-): skip
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
while (*s && *s != ',') s++; // #1: (-): skip
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
while (*s && *s != ',') s++; // #1: (-): skip
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
// stdlat
|
||||||
|
int stdlat = nmea.parseFloat(s, 1, NULL);
|
||||||
|
while (*s && *s != ',') s++;
|
||||||
|
if (*s == ',') s++; else return;
|
||||||
|
// stdlong
|
||||||
|
int stdlon = nmea.parseFloat(s, 1, NULL);
|
||||||
|
// calculate position error as 1-signma horizontal RMS
|
||||||
|
// I guess that is equivalent to Androids getAccurac()?
|
||||||
|
int poserr = 0;
|
||||||
|
if (stdlat < 10000 && stdlon < 10000) { // larger errors: no GPS fix, avoid overflow in *
|
||||||
|
poserr = (int)(sqrt(0.5 * (stdlat * stdlat + stdlon * stdlon)));
|
||||||
|
}
|
||||||
|
//Serial.printf("\nHorizontal accuracy: %d, %d => %.1fm\n", stdlat, stdlon, 0.1*poserr);
|
||||||
|
gpsPos.accuracy = poserr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 deg = aprox. 100 km ==> approx. 200m
|
||||||
|
#define AUTO_CHASE_THRESHOLD 0.002
|
||||||
|
|
||||||
|
//#define DEBUG_GPS
|
||||||
|
static bool gpsCourseOld;
|
||||||
|
static int lastCourse;
|
||||||
|
void gpsTask(void *parameter) {
|
||||||
|
nmea.setUnknownSentenceHandler(unkHandler);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
while (Serial2.available()) {
|
||||||
|
char c = Serial2.read();
|
||||||
|
//Serial.print(c);
|
||||||
|
if (nmea.process(c)) {
|
||||||
|
gpsPos.valid = nmea.isValid();
|
||||||
|
if (gpsPos.valid) {
|
||||||
|
gpsPos.lon = nmea.getLongitude() * 0.000001;
|
||||||
|
gpsPos.lat = nmea.getLatitude() * 0.000001;
|
||||||
|
long alt = 0;
|
||||||
|
nmea.getAltitude(alt);
|
||||||
|
gpsPos.alt = (int)(alt / 1000);
|
||||||
|
gpsPos.course = (int)(nmea.getCourse() / 1000);
|
||||||
|
gpsCourseOld = false;
|
||||||
|
if (gpsPos.course == 0) {
|
||||||
|
// either north or not new
|
||||||
|
if (lastCourse != 0) // use old value...
|
||||||
|
{
|
||||||
|
gpsCourseOld = true;
|
||||||
|
gpsPos.course = lastCourse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gpsPos.lon == 0 && gpsPos.lat == 0) gpsPos.valid = false;
|
||||||
|
}
|
||||||
|
/* Check if home */
|
||||||
|
if(gpsPos.valid) {
|
||||||
|
float d = fabs(gpsPos.lon - sonde.config.rxlon);
|
||||||
|
d += fabs(gpsPos.lat - sonde.config.rxlat);
|
||||||
|
if(!posInfo.chase && d > AUTO_CHASE_THRESHOLD) {
|
||||||
|
posInfo = gpsPos;
|
||||||
|
posInfo.chase = 1;
|
||||||
|
} else if ( posInfo.chase && d < AUTO_CHASE_THRESHOLD/2 ) {
|
||||||
|
fixedToPosInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gpsPos.hdop = nmea.getHDOP();
|
||||||
|
gpsPos.sat = nmea.getNumSatellites();
|
||||||
|
gpsPos.speed = nmea.getSpeed() / 1000.0 * 0.514444; // speed is in m/s nmea.getSpeed is in 0.001 knots
|
||||||
|
#ifdef DEBUG_GPS
|
||||||
|
uint8_t hdop = nmea.getHDOP();
|
||||||
|
Serial.printf(" =>: valid: %d N %f E %f alt %d course:%d dop:%d\n", gpsPos.valid ? 1 : 0, gpsPos.lat, gpsPos.lon, gpsPos.alt, gpsPos.course, hdop);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define UBX_SYNCH_1 0xB5
|
||||||
|
#define UBX_SYNCH_2 0x62
|
||||||
|
uint8_t ubx_set9k6[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8F};
|
||||||
|
uint8_t ubx_factorydef[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x09, 13, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0x7c };
|
||||||
|
uint8_t ubx_hardreset[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x04, 4, 0, 0xff, 0xff, 0, 0, 0x0C, 0x5D };
|
||||||
|
// GPGST: Class 0xF0 Id 0x07
|
||||||
|
uint8_t ubx_enable_gpgst[] = {UBX_SYNCH_1, UBX_SYNCH_2, 0x06, 0x01, 3, 0, 0xF0, 0x07, 2, 0x03, 0x1F};
|
||||||
|
|
||||||
|
void dumpGPS() {
|
||||||
|
while (Serial2.available()) {
|
||||||
|
char c = Serial2.read();
|
||||||
|
Serial.printf("%02x ", (uint8_t)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void initGPS() {
|
||||||
|
if (sonde.config.gps_rxd < 0) return; // GPS disabled
|
||||||
|
if (sonde.config.gps_txd >= 0) { // TX enable, thus try setting baud to 9600 and do a factory reset
|
||||||
|
File testfile = SPIFFS.open("/GPSRESET", FILE_READ);
|
||||||
|
if (testfile && !testfile.isDirectory()) {
|
||||||
|
testfile.close();
|
||||||
|
Serial.println("GPS resetting baud to 9k6...");
|
||||||
|
/* TODO: debug:
|
||||||
|
Sometimes I have seen the Serial2.begin to cause a reset
|
||||||
|
Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1)
|
||||||
|
Backtrace: 0x40081d2f:0x3ffc11b0 0x40087969:0x3ffc11e0 0x4000bfed:0x3ffb1db0 0x4008b7dd:0x3ffb1dc0 0x4017afee:0x3ffb1de0 0x4017b04b:0x3ffb1e20 0x4010722b:0x3ffb1e50 0x40107303:0x3ffb1e70 0x4010782d:0x3ffb1e90 0x40103814:0x3ffb1ed0 0x400d8772:0x3ffb1f10 0x400d9057:0x3ffb1f60 0x40107aca:0x3ffb1fb0 0x4008a63e:0x3ffb1fd0
|
||||||
|
#0 0x40081d2f:0x3ffc11b0 in _uart_isr at /Users/hansi/.platformio/packages/framework-arduinoespressif32/cores/esp32/esp32-hal-uart.c:464
|
||||||
|
#1 0x40087969:0x3ffc11e0 in _xt_lowint1 at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/xtensa_vectors.S:1154
|
||||||
|
#2 0x4000bfed:0x3ffb1db0 in ?? ??:0
|
||||||
|
#3 0x4008b7dd:0x3ffb1dc0 in vTaskExitCritical at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c:3507
|
||||||
|
#4 0x4017afee:0x3ffb1de0 in esp_intr_alloc_intrstatus at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/intr_alloc.c:784
|
||||||
|
#5 0x4017b04b:0x3ffb1e20 in esp_intr_alloc at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/esp32/intr_alloc.c:784
|
||||||
|
#6 0x4010722b:0x3ffb1e50 in uartEnableInterrupt at /Users/hansi/.platformio/packages/framework-arduinoespressif32/cores/esp32/esp32-hal-uart.c:464
|
||||||
|
#7 0x40107303:0x3ffb1e70 in uartAttachRx at /Users/hansi/.platformio/packages/framework-arduinoespressif32/cores/esp32/esp32-hal-uart.c:464
|
||||||
|
#8 0x4010782d:0x3ffb1e90 in uartBegin at /Users/hansi/.platformio/packages/framework-arduinoespressif32/cores/esp32/esp32-hal-uart.c:464
|
||||||
|
#9 0x40103814:0x3ffb1ed0 in HardwareSerial::begin(unsigned long, unsigned int, signed char, signed char, bool, unsigned long) at /Users/hansi/.platformio/packages/framework-arduinoespressif32/cores/esp32/HardwareSerial.cpp:190
|
||||||
|
*/
|
||||||
|
Serial2.begin(115200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
delay(200);
|
||||||
|
Serial2.begin(38400, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
delay(200);
|
||||||
|
Serial2.begin(19200, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
Serial2.write(ubx_set9k6, sizeof(ubx_set9k6));
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
delay(1000);
|
||||||
|
dumpGPS();
|
||||||
|
Serial.println("GPS factory reset...");
|
||||||
|
Serial2.write(ubx_factorydef, sizeof(ubx_factorydef));
|
||||||
|
delay(1000);
|
||||||
|
dumpGPS();
|
||||||
|
delay(1000);
|
||||||
|
dumpGPS();
|
||||||
|
delay(1000);
|
||||||
|
dumpGPS();
|
||||||
|
SPIFFS.remove("/GPSRESET");
|
||||||
|
} else if (testfile) {
|
||||||
|
Serial.println("GPS reset file: not found/isdir");
|
||||||
|
testfile.close();
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
}
|
||||||
|
// Enable GPGST messages
|
||||||
|
Serial2.write(ubx_enable_gpgst, sizeof(ubx_enable_gpgst));
|
||||||
|
} else {
|
||||||
|
Serial2.begin(9600, SERIAL_8N1, sonde.config.gps_rxd, sonde.config.gps_txd);
|
||||||
|
}
|
||||||
|
xTaskCreate( gpsTask, "gpsTask",
|
||||||
|
5000, /* stack size */
|
||||||
|
NULL, /* paramter */
|
||||||
|
1, /* priority */
|
||||||
|
NULL); /* task handle*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Getting GPS data from App (phone)
|
||||||
|
|
||||||
|
void parseGpsJson(char *data, int len) {
|
||||||
|
char *key = NULL;
|
||||||
|
char *value = NULL;
|
||||||
|
// very simple json parser: look for ", then key, then ", then :, then number, then , or } or \0
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (key == NULL) {
|
||||||
|
if (data[i] != '"') continue;
|
||||||
|
key = data + i + 1;
|
||||||
|
i += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (value == NULL) {
|
||||||
|
if (data[i] != ':') continue;
|
||||||
|
value = data + i + 1;
|
||||||
|
i += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (data[i] == ',' || data[i] == '}' || data[i] == 0) {
|
||||||
|
// get value
|
||||||
|
double val = strtod(value, NULL);
|
||||||
|
// get data
|
||||||
|
if (strncmp(key, "lat", 3) == 0) {
|
||||||
|
gpsPos.lat = val;
|
||||||
|
}
|
||||||
|
else if (strncmp(key, "lon", 3) == 0) {
|
||||||
|
gpsPos.lon = val;
|
||||||
|
}
|
||||||
|
else if (strncmp(key, "alt", 3) == 0) {
|
||||||
|
gpsPos.alt = (int)val;
|
||||||
|
}
|
||||||
|
else if (strncmp(key, "course", 6) == 0) {
|
||||||
|
gpsPos.course = (int)val;
|
||||||
|
}
|
||||||
|
gpsPos.valid = true;
|
||||||
|
|
||||||
|
// next item:
|
||||||
|
if (data[i] != ',') break;
|
||||||
|
key = NULL;
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gpsPos.lat == 0 && gpsPos.lon == 0) gpsPos.valid = false;
|
||||||
|
Serial.printf("Parse result: lat=%f, lon=%f, alt=%d, valid=%d\n", gpsPos.lat, gpsPos.lon, gpsPos.alt, gpsPos.valid);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
#ifndef _posinfo_h
|
||||||
|
#define _posinfo_h
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "Sonde.h"
|
||||||
|
#include <SPIFFS.h>
|
||||||
|
|
||||||
|
enum { SH_LOC_OFF, SH_LOC_FIXED, SH_LOC_CHASE, SH_LOC_AUTO };
|
||||||
|
|
||||||
|
|
||||||
|
// Handling of station position (GPS, fixed location)
|
||||||
|
|
||||||
|
struct StationPos {
|
||||||
|
double lat;
|
||||||
|
double lon;
|
||||||
|
int alt;
|
||||||
|
float speed;
|
||||||
|
int16_t course;
|
||||||
|
int16_t accuracy;
|
||||||
|
int16_t hdop;
|
||||||
|
int8_t sat;
|
||||||
|
int8_t valid;
|
||||||
|
int8_t chase;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct StationPos gpsPos, posInfo;
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize GPS chip
|
||||||
|
void initGPS();
|
||||||
|
|
||||||
|
// Update position from app (if not local GPS chip)
|
||||||
|
void parseGpsJson(char *data, int len);
|
||||||
|
|
||||||
|
// Update position from static config
|
||||||
|
void fixedToPosInfo();
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,3 +1,6 @@
|
||||||
|
#include "../features.h"
|
||||||
|
#if FEATURE_RS92
|
||||||
|
|
||||||
/* SPDX-License-Identifier: GPL-3.0
|
/* SPDX-License-Identifier: GPL-3.0
|
||||||
* based on https://github.com/rs1729/RS/blob/master/rs92/rs92gps.c
|
* based on https://github.com/rs1729/RS/blob/master/rs92/rs92gps.c
|
||||||
*
|
*
|
||||||
|
@ -1202,3 +1205,4 @@ void get_eph(const char *file) {
|
||||||
if (!option_der) d_err = 1000;
|
if (!option_der) d_err = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const char *version_name = "rdzTTGOsonde";
|
const char *version_name = "rdzTTGOsonde";
|
||||||
const char *version_id = "master_v0.9.3";
|
const char *version_id = "master_v0.9.4";
|
||||||
const int SPIFFS_MAJOR=2;
|
const int SPIFFS_MAJOR=2;
|
||||||
const int SPIFFS_MINOR=17;
|
const int SPIFFS_MINOR=17;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x140000,
|
||||||
|
app1, app, ota_1, 0x150000,0x140000,
|
||||||
|
spiffs, data, spiffs, 0x290000,0x160000,
|
||||||
|
coredump, data, coredump,0x3F0000,0x10000,
|
|
|
@ -17,16 +17,17 @@ data_dir = RX_FSK/data
|
||||||
lib_deps_builtin =
|
lib_deps_builtin =
|
||||||
; src
|
; src
|
||||||
lib_deps_external =
|
lib_deps_external =
|
||||||
olikraus/U8g2 @ ^2.28.8
|
olikraus/U8g2 @ ^2.35.8
|
||||||
AXP202X_Library
|
|
||||||
stevemarple/MicroNMEA @ ^2.0.5
|
stevemarple/MicroNMEA @ ^2.0.5
|
||||||
me-no-dev/ESP Async WebServer @ ^1.2.3
|
; This is an old version with regex support unconditionally compiled in (adds >100k of code)
|
||||||
https://github.com/moononournation/Arduino_GFX#v1.1.5
|
; me-no-dev/ESP Async WebServer @ ^1.2.3
|
||||||
|
https://github.com/me-no-dev/ESPAsyncWebServer/archive/refs/heads/master.zip
|
||||||
|
; https://github.com/moononournation/Arduino_GFX#v1.1.5
|
||||||
|
https://github.com/moononournation/Arduino_GFX#v1.2.9
|
||||||
https://github.com/dx168b/async-mqtt-client
|
https://github.com/dx168b/async-mqtt-client
|
||||||
|
|
||||||
[env:ttgo-lora32]
|
[env:ttgo-lora32]
|
||||||
platform = https://github.com/platformio/platform-espressif32.git#v3.3.2
|
platform = https://github.com/platformio/platform-espressif32.git#v6.4.0
|
||||||
#platform = https://github.com/platformio/platform-espressif32.git#v4.4.0
|
|
||||||
board = ttgo-lora32-v1
|
board = ttgo-lora32-v1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
@ -35,6 +36,8 @@ lib_deps =
|
||||||
${extra.lib_deps_external}
|
${extra.lib_deps_external}
|
||||||
paulstoffregen/Time@^1.6.0
|
paulstoffregen/Time@^1.6.0
|
||||||
lib_ignore = Time
|
lib_ignore = Time
|
||||||
|
; Same as with ArduinoIDE. Saves around 27k code
|
||||||
|
build_flags = -DCORE_DEBUG_LEVEL=0
|
||||||
|
|
||||||
; Add / remove the following two lines for separate fonts partition in flash
|
; Add / remove the following two lines for separate fonts partition in flash
|
||||||
; after changes:
|
; after changes:
|
||||||
|
@ -46,3 +49,7 @@ lib_ignore = Time
|
||||||
;
|
;
|
||||||
extra_scripts = post:scripts/makefontpartition.py
|
extra_scripts = post:scripts/makefontpartition.py
|
||||||
;board_build.partitions = partition-fonts.csv
|
;board_build.partitions = partition-fonts.csv
|
||||||
|
|
||||||
|
; Uncomment the following if you want to have the partition scheme used in the ESP32 board version 2.0.x of ArduinoIDE
|
||||||
|
; board_build.partitions = partitions-esp32v2.csv
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import requests
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
import tempfile
|
||||||
import esptool
|
import esptool
|
||||||
|
|
||||||
ttgohost = "rdzsonde.local"
|
ttgohost = "rdzsonde.local"
|
||||||
|
@ -56,6 +57,7 @@ if len(sys.argv)<=2:
|
||||||
print("or: ",sys.argv[0]," <get|put> file {filename}");
|
print("or: ",sys.argv[0]," <get|put> file {filename}");
|
||||||
print("or: ",sys.argv[0]," update <devel-xxx|master-yyy>");
|
print("or: ",sys.argv[0]," update <devel-xxx|master-yyy>");
|
||||||
print("or: ",sys.argv[0]," <backup|restore> file.bin");
|
print("or: ",sys.argv[0]," <backup|restore> file.bin");
|
||||||
|
print("or: ",sys.argv[0]," uploadfs directory");
|
||||||
print("\n",
|
print("\n",
|
||||||
" screens is screens1.txt, screens2.txt, screens3.txt");
|
" screens is screens1.txt, screens2.txt, screens3.txt");
|
||||||
print(" networks is networks.txt (Wifi ssid and password)")
|
print(" networks is networks.txt (Wifi ssid and password)")
|
||||||
|
@ -94,6 +96,52 @@ if sys.argv[1]=="update":
|
||||||
esptool.main()
|
esptool.main()
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def getpartinfo(partname):
|
||||||
|
import gen_esp32part as pt
|
||||||
|
# flash complete file system
|
||||||
|
# automatically get file system parameters from ESP (i.e. you need to program the partition table first)
|
||||||
|
if False:
|
||||||
|
tmpdir = tempfile.mkdtemp()
|
||||||
|
partbin = os.path.join(tmpdir, "partition.bin")
|
||||||
|
sys._argv = sys.argv[:]
|
||||||
|
sys.argv=[sys._argv[0], "--chip", "esp32", "--baud", "921600", "--before", "default_reset",
|
||||||
|
"--after", "no_reset", "read_flash", "0x8000", "0x1000", partbin]
|
||||||
|
esptool.main()
|
||||||
|
else:
|
||||||
|
# test only
|
||||||
|
partbin="partitions-esp32v2.csv"
|
||||||
|
with open(partbin,"rb") as f:
|
||||||
|
table, input_is_binary = pt.PartitionTable.from_file(f)
|
||||||
|
print("Partition table:")
|
||||||
|
tab = table.to_csv()
|
||||||
|
print(tab)
|
||||||
|
OFFSET = -1
|
||||||
|
SIZE = -1
|
||||||
|
for line in tab.split("\n"):
|
||||||
|
if line.startswith(partname):
|
||||||
|
l = line.split(",")
|
||||||
|
OFFSET = int(l[3],0)
|
||||||
|
SIZE = l[4]
|
||||||
|
mult = 1
|
||||||
|
if SIZE[-1].upper() == 'K':
|
||||||
|
SIZE = SIZE[:-1]
|
||||||
|
mult = 1024
|
||||||
|
print("SIZE is:"+SIZE+"!")
|
||||||
|
SIZE = int(SIZE,0) * mult
|
||||||
|
|
||||||
|
print("File system at ",hex(OFFSET)," size=",hex(SIZE))
|
||||||
|
return [OFFSET, SIZE]
|
||||||
|
|
||||||
|
#OFFSET="0x3F0000"
|
||||||
|
#SIZE="0x10000"
|
||||||
|
|
||||||
|
if sys.argv[1]=="uploadfs":
|
||||||
|
(offset, size) = getpartinfo("spiffs")
|
||||||
|
print("Using offset ",offset,"; size is ",size)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
addrinfo = socket.gethostbyname(ttgohost)
|
addrinfo = socket.gethostbyname(ttgohost)
|
||||||
url = "http://"+addrinfo+"/"
|
url = "http://"+addrinfo+"/"
|
||||||
print("Using URL ",url)
|
print("Using URL ",url)
|
||||||
|
|
Ładowanie…
Reference in New Issue