Squashed commit of the following:

commit fcaf88779d
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)

commit 9c7491d389
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Sat Jan 6 23:51:44 2024 +0000

    better license info on external libraries

commit 12ede0e81d
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Mon Dec 18 19:12:36 2023 +0100

    esp32 version update

commit 1687117bec
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Dec 12 19:36:47 2023 +0000

    tentative fix of M20 misclassification as M10 (untested)

commit ff5aec544e
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Dec 12 19:27:23 2023 +0000

    tentative fix of M20 misclassification as M10 (untested)

commit 2b88e072ac
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

commit 8ee071de35
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Sun Dec 3 22:45:44 2023 +0000

    T-Beam 1.2: charge battery fix

commit 681f436767
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Sun Dec 3 16:00:13 2023 +0000

    newer library versions

commit 6551fa0b5d
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Fri Nov 10 09:43:02 2023 +0000

    chasemapper: id format with type, as in auto_rx

commit e5c2e2db77
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Aug 29 20:15:53 2023 +0000

    more explanation in About tabw

commit aec4d39867
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Aug 29 01:00:53 2023 +0000

    fix travis build / wget issue with github

commit d7026abb7b
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Aug 29 00:22:48 2023 +0000

    fix bug in eph config editor

commit 6c98891b63
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Mon Aug 28 12:35:06 2023 +0000

    AXP2101: add missing irq handler

commit c1231a11d4
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Mon Aug 28 12:02:36 2023 +0000

    bugfix (APX2101 related)

commit 86263a7ad1
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Mon Aug 28 10:13:39 2023 +0000

    fix

commit 35156948cb
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Mon Aug 28 10:07:09 2023 +0000

    yet another fix for ftp eph

commit 3ddbebf2fc
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Sat Aug 26 23:33:33 2023 +0000

    untested axp2101 support

commit 60e97d917b
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Sat Aug 26 17:19:38 2023 +0000

    pmu reorg, preparing for axp2101

commit 082b6ccdf5
Author: Hansi, dl9rdz <dl9rdz@darc.de>
Date:   Tue Aug 22 22:28:37 2023 +0000

    fix posInfo bug; aprs timeout convert seconds to ms

commit deec0d362f
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
master
Hansi, dl9rdz 2024-01-07 12:32:26 +00:00
rodzic 6cf330b143
commit 5ce1d36b97
43 zmienionych plików z 2345 dodań i 2722 usunięć

Wyświetl plik

@ -1,3 +1,9 @@
# safelist
branches:
only:
- master
- devel
language: c
dist: focal
os: linux
@ -17,20 +23,20 @@ before_install:
- tar xf arduino-1.8.16-linux64.tar.xz
- sudo mv arduino-1.8.16 /usr/local/share/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
- rm master.zip
- 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
- rm master.zip
- 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 https://github.com/lewisxhe/AXP202X_Library/archive/refs/tags/V1.1.3.zip
- wget --secure-protocol=TLSv1_2 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/lewisxhe/AXP202X_Library/archive/refs/tags/V1.1.3.zip
- unzip V1.1.3.zip
- 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
- rm master.zip
- 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 --install-boards esp32:esp32:1.0.6 --save-prefs
- 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 "GFX Library for Arduino:1.1.5"
- arduino --install-library "GFX Library for Arduino:1.2.9"
script:
- arduino --board esp32:esp32:t-beam --verify $PWD/RX_FSK/RX_FSK.ino
- ESPPATH=`arduino --get-pref runtime.tools.xtensa-esp32-elf-gcc.path`

Wyświetl plik

@ -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
and licensed under
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
https://github.com/Turbo87/sidebar-v2/
and licensed under
MIT License
- General purpose Reed-Solomon decoder for 8-bit symbols or less
Copyright 2003 Phil Karn, KA9Q
May be used under the terms of the GNU Lesser General Public License (LGPL) - lgpl-2.1.txt
- 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

Wyświetl plik

@ -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.

Wyświetl plik

@ -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.

Wyświetl plik

@ -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.

174
Licenses/apache.txt 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -42,6 +42,7 @@ var cfgs = [
[ "axudp.port", "AXUDP port"],
[ "axudp.highrate", "Rate limit"],
[ "tcp.active", "APRS TCP active"],
[ "tcp.timeout", "APRS TCP timeout [s] (0=off, 25=on)"],
[ "tcp.host", "APRS TCP host"],
[ "tcp.port", "APRS TCP port"],
[ "tcp.highrate", "Rate limit"],

Wyświetl plik

@ -15,6 +15,7 @@ document.addEventListener("DOMContentLoaded", function(){
fetch('live.json')
.then((response) => response.json())
.then((data) => {
if (data.gps===undefined) { data.gps={} };
console.log(data.gps.lat, data.gps.lon, data.sonde.ser);
if( (data.sonde.ser||'')=='' && !(data.gps.lat===undefined) ) {
urlarg = maps[maptype][2](data.gps.lat, data.gps.lon);

Wyświetl plik

@ -2,12 +2,17 @@
// Configuration flags for including/excluding fuctionality from the compiled binary
// set flag to 0 for exclude/1 for include
/* data feed to sondehubv2 */
/* needs about 4k4 code, 200b data, 200b stack, 200b heap */
// Selection of data output connectors to be included in firmware
// APRS includes AXUDP (e.g. for aprsmap) and APRS-IS (TCP) (e.g. for wettersonde.net, radiosondy.info)
#define FEATURE_SONDEHUB 1
#define FEATURE_CHASEMAPPER 1
#define FEATURE_MQTT 1
#define FEATURE_SDCARD 0
#define FEATURE_APRS 1
// Additional optional components
#define FEATURE_RS92 1
/* Most recent version support fonts in a dedicated flash parition "fonts".

Wyświetl plik

@ -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

Wyświetl plik

@ -2,10 +2,10 @@
#include <U8x8lib.h>
#include <U8g2lib.h>
#include <SPIFFS.h>
#include <axp20x.h>
#include <MicroNMEA.h>
#include "Display.h"
#include "Sonde.h"
#include "pmu.h"
int readLine(Stream &stream, char *buffer, int maxlen);
@ -22,8 +22,7 @@ extern const char *version_id;
extern Sonde sonde;
extern AXP20X_Class axp;
extern bool axp192_found;
extern PMU *pmu;
extern SemaphoreHandle_t axpSemaphore;
extern xSemaphoreHandle globalLock;
@ -33,8 +32,6 @@ extern xSemaphoreHandle globalLock;
} while (xSemaphoreTake(globalLock, portMAX_DELAY) != pdPASS)
#define SPI_MUTEX_UNLOCK() xSemaphoreGive(globalLock)
struct GpsPos gpsPos;
//SPIClass spiDisp(HSPI);
byte myIP_tiles[8*11];
@ -1670,13 +1667,14 @@ void Display::drawGPS(DispEntry *de) {
void Display::drawBatt(DispEntry *de) {
float val;
char buf[30];
if (!axp192_found) {
if (!pmu) {
if (sonde.config.batt_adc<0) return;
switch (de->extra[0])
{
case 'V':
val = (float)(analogRead(sonde.config.batt_adc)) / 4095 * 2 * 3.3 * 1.1;
snprintf(buf, 30, "%.2f%s", val, de->extra + 1);
Serial.printf("Batt: %s", buf);
break;
default:
*buf = 0;
@ -1684,51 +1682,67 @@ void Display::drawBatt(DispEntry *de) {
rdis->setFont(de->fmt);
drawString(de, buf);
} else {
*buf = 0;
xSemaphoreTake( axpSemaphore, portMAX_DELAY );
switch(de->extra[0]) {
case 'S':
if(!axp.isBatteryConnect()) {
if(axp.isVBUSPlug()) { strcpy(buf, "U"); }
if(!pmu->isBatteryConnected()) {
if(pmu->isVbusIn()) { strcpy(buf, "U"); }
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
Serial.printf("Battery: %s\n", buf);
break;
case 'V':
val = axp.getBattVoltage();
val = pmu->getBattVoltage();
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
Serial.printf("Vbatt: %s\n", buf);
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);
Serial.printf("Icharge: %s\n", buf);
break;
case 'D':
val = axp.getBattDischargeCurrent();
case 'D':
val = pmu->getBattDischargeCurrent();
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
Serial.printf("Idischarge: %s\n", buf);
break;
case 'U':
case 'U':
if(sonde.config.type == TYPE_M5_CORE2) {
val = axp.getAcinVoltage();
val = pmu->getAcinVoltage();
} else {
val = axp.getVbusVoltage();
val = pmu->getVbusVoltage();
}
snprintf(buf, 30, "%.2f%s", val/1000, de->extra+1);
Serial.printf("Vbus: %s\n", buf);
break;
case 'I':
case 'I':
if(sonde.config.type == TYPE_M5_CORE2) {
val = axp.getAcinCurrent();
val = pmu->getAcinCurrent();
} else {
val = axp.getVbusCurrent();
val = pmu->getVbusCurrent();
}
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
Serial.printf("Ibus: %s\n", buf);
break;
case 'T':
val = axp.getTemp(); // fixed in newer versions of libraray: -144.7 no longer needed here!
case 'T':
val = pmu->getTemperature();
snprintf(buf, 30, "%.2f%s", val, de->extra+1);
Serial.printf("temp: %s\n", buf);
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 );
rdis->setFont(de->fmt);
drawString(de, buf);

Wyświetl plik

@ -9,18 +9,7 @@
#include <U8x8lib.h>
#include <SPIFFS.h>
struct GpsPos {
double lat;
double lon;
int alt;
int course;
float speed;
int sat;
int accuracy;
int hdop;
int valid;
};
extern struct GpsPos gpsPos;
#include "posinfo.h"
#define WIDTH_AUTO 9999
struct DispEntry {

Wyświetl plik

@ -304,6 +304,9 @@ int M10M20::decodeframeM10(uint8_t *data) {
Serial.println("Decoding...");
//SondeInfo *si = sonde.si();
SondeData *si = &(sonde.si()->d);
// Set type info to M10
memcpy(si->typestr, "M10 ", 5);
si->subtype = 1; // subtype 1: M10
// Its a M10
// getid...
@ -441,7 +444,7 @@ void M10M20::processM10data(uint8_t dt)
rxsearching = false;
rxbitc = 0;
rxp = 0;
isM20 = false;
//isM20 = false;
headerDetected = 1;
#if 1
int rssi=sx1278.getRSSI();
@ -463,17 +466,17 @@ void M10M20::processM10data(uint8_t dt)
// 64 9F 20 => M10
// 64 49 0x => M10 (?) -- not used here
// 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) {
memcpy(sonde.si()->d.typestr, "M20 ", 5);
sonde.si()->d.subtype = 2;
if(rxp>=M20_FRAMELEN) {
rxsearching = true;
haveNewFrame = decodeframeM20(dataptr);
}
} else {
memcpy(sonde.si()->d.typestr, "M10 ", 5);
sonde.si()->d.subtype = 1;
if(rxp>=M10_FRAMELEN) {
rxsearching = true;
haveNewFrame = decodeframeM10(dataptr);
@ -578,6 +581,8 @@ int M10M20::decodeframeM20(uint8_t *data) {
Serial.println("Decoding...");
// Its a M20
memcpy(si->typestr, "M20 ", 5);
si->subtype = 2; // subtype 2: M20
// getid...
// TODO: Adjust ID calculation and serial number reconstruction
char ids[11]={'M','E','0','0','0','0','0','0','0','0','0'};

Wyświetl plik

@ -1,3 +1,5 @@
#include "../features.h"
#if FEATURE_RS92
/* RS92 decoder functions */
#include "RS92.h"
@ -587,3 +589,4 @@ int RS92::waitRXcomplete() {
RS92 rs92 = RS92();
#endif

Wyświetl plik

@ -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 sondeTypeChar[NSondeTypes] = { 'D', '4', 'R', 'M', 'M', '2', '3' };
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 };
const char *fingerprintText[]={
@ -258,7 +259,7 @@ void Sonde::defaultConfig() {
config.tcpfeed.port = 12345;
config.tcpfeed.highrate = 10;
config.kisstnc.active = 0;
strcpy(config.ephftp,"igs.bkg.bund.de/IGS/BRDC/");
strcpy(config.ephftp,DEFEPH);
config.mqtt.active = 0;
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.fimaxdist==0) config.sondehub.fimaxdist = 150;
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) {
while(*cfg==' '||*cfg=='\t') cfg++;

Wyświetl plik

@ -191,6 +191,7 @@ struct st_feedinfo {
int lowrate;
int highrate;
int lowlimit;
int timeout;
};
// maybe extend for external Bluetooth interface?
@ -281,7 +282,7 @@ typedef struct st_rdzconfig {
struct st_dfmconfig dfm;
struct st_m10m20config m10m20;
struct st_mp3hconfig mp3h;
char ephftp[40];
char ephftp[80];
// data feed configuration
// for now, one feed for each type is enough, but might get extended to more?
char call[10]; // APRS callsign

Wyświetl plik

@ -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

Wyświetl plik

@ -16,6 +16,7 @@
#include <unistd.h>
#include <inttypes.h>
#include "aprs.h"
#include "RS41.h"
extern const char *version_name;
extern const char *version_id;

Wyświetl plik

@ -1,8 +1,8 @@
#ifndef _aprs_h
#define _aprs_h
#include "Sonde.h"
#include "RS41.h"
#define APRS_MAXLEN 201

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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 WiFiUDP udp;
int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
void ConnChasemapper::init() {
}
void ConnChasemapper::netsetup() {
}
void ConnChasemapper::updateSonde(SondeInfo *si) {
char buf[1024];
struct tm tim;
time_t t = si->d.time;
@ -11,8 +23,16 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
if (TYPE_IS_METEO(realtype)) {
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\","
"\"callsign\": \"%s\","
"\"callsign\": \"%s%s\","
"\"latitude\": %.5f,"
"\"longitude\": %.5f,"
"\"altitude\": %d,"
@ -21,6 +41,7 @@ int Chasemapper::send(WiFiUDP &udp, SondeInfo *si) {
"\"time\": \"%02d:%02d:%02d\","
"\"model\": \"%s\","
"\"freq\": \"%.3f MHz\"",
prefix,
si->d.ser,
si->d.lat,
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.write((const uint8_t *)buf, strlen(buf));
udp.endPacket();
return 0;
}
void ConnChasemapper::updateStation(PosInfo *pi) {
}
ConnChasemapper connChasemapper;
#endif

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

38
RX_FSK/src/conn.h 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -1,3 +1,6 @@
#include "../features.h"
#if FEATURE_RS92
#include "time.h"
#include "geteph.h"
#include <SPIFFS.h>
@ -14,7 +17,7 @@ extern WiFiClient client;
char outbuf[128];
uint8_t ephstate = EPH_NOTUSED;
//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() {
String s = client.readStringUntil('\n');
@ -83,22 +86,25 @@ void geteph() {
Serial.println("cannot open file\n");
return;
}
char host[252];
strcpy(host, sonde.config.ephftp);
char *buf = strchr(host, '/');
if(!buf) { Serial.println("Invalid FTP host config"); return; }
*buf = 0;
buf++;
char host[100];
char buf[200];
char *ptr = strchr(sonde.config.ephftp, '/');
if(!ptr) { Serial.println("Invalid FTP host config"); return; }
int hlen = ptr - sonde.config.ephftp;
strncpy(host, sonde.config.ephftp, hlen);
host[hlen] = 0;
snprintf(buf, 200, ptr+1, year, day, year-2000);
uint8_t dispw, disph, dispxs, dispys;
disp.rdis->getDispSize(&disph, &dispw, &dispxs, &dispys);
disp.rdis->clear();
disp.rdis->setFont(FONT_SMALL);
disp.rdis->drawString(0, 0, host);
// fetch rinex from server
char *ptr = buf + strlen(buf);
snprintf(ptr, 128, "%04d/%03d/brdc%03d0.%02dn.gz", year, day, day, year-2000);
// char *ptr = buf + strlen(buf);
// 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");
disp.rdis->drawString(0, 1*dispys, ptr+9);
disp.rdis->drawString(0, 1*dispys, buf+9);
if(!client.connect(host, 21)) {
Serial.printf("FTP connection to %s failed\n", host);
@ -236,3 +242,4 @@ void geteph() {
file.close();
ofile.close();
}
#endif

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -1,3 +1,6 @@
#include "../features.h"
#if FEATURE_RS92
/* SPDX-License-Identifier: GPL-3.0
* 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;
}
#endif

545
RX_FSK/src/pmu.cpp 100644
Wyświetl plik

@ -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; }

115
RX_FSK/src/pmu.h 100644
Wyświetl plik

@ -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);
};

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -1,3 +1,6 @@
#include "../features.h"
#if FEATURE_RS92
/* SPDX-License-Identifier: GPL-3.0
* 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;
}
#endif

Wyświetl plik

@ -1,4 +1,4 @@
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_MINOR=17;

Wyświetl plik

@ -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,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x140000
5 app1 app ota_1 0x150000 0x140000
6 spiffs data spiffs 0x290000 0x160000
7 coredump data coredump 0x3F0000 0x10000

Wyświetl plik

@ -17,16 +17,17 @@ data_dir = RX_FSK/data
lib_deps_builtin =
; src
lib_deps_external =
olikraus/U8g2 @ ^2.28.8
AXP202X_Library
olikraus/U8g2 @ ^2.35.8
stevemarple/MicroNMEA @ ^2.0.5
me-no-dev/ESP Async WebServer @ ^1.2.3
https://github.com/moononournation/Arduino_GFX#v1.1.5
; This is an old version with regex support unconditionally compiled in (adds >100k of code)
; 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
[env:ttgo-lora32]
platform = https://github.com/platformio/platform-espressif32.git#v3.3.2
#platform = https://github.com/platformio/platform-espressif32.git#v4.4.0
platform = https://github.com/platformio/platform-espressif32.git#v6.4.0
board = ttgo-lora32-v1
framework = arduino
monitor_speed = 115200
@ -35,6 +36,8 @@ lib_deps =
${extra.lib_deps_external}
paulstoffregen/Time@^1.6.0
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
; after changes:
@ -46,3 +49,7 @@ lib_ignore = Time
;
extra_scripts = post:scripts/makefontpartition.py
;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

48
scripts/ttgoconfig 100644 → 100755
Wyświetl plik

@ -3,6 +3,7 @@ import requests
import sys
import os
import socket
import tempfile
import esptool
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]," update <devel-xxx|master-yyy>");
print("or: ",sys.argv[0]," <backup|restore> file.bin");
print("or: ",sys.argv[0]," uploadfs directory");
print("\n",
" screens is screens1.txt, screens2.txt, screens3.txt");
print(" networks is networks.txt (Wifi ssid and password)")
@ -94,6 +96,52 @@ if sys.argv[1]=="update":
esptool.main()
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)
url = "http://"+addrinfo+"/"
print("Using URL ",url)