Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea79561bcf | ||
|
|
cbceec1887 | ||
|
|
e1ee1c560e | ||
|
|
97fb018d51 | ||
|
|
b987f7c21c | ||
|
|
fb2a0865ee | ||
|
|
8ef86500db | ||
|
|
0d2ff764ea | ||
|
|
1014df8ec7 | ||
|
|
9ee412126f | ||
|
|
24e5b5afe6 | ||
|
|
fa1c728187 | ||
|
|
e22e6e8ab3 | ||
|
|
7c979dbd01 |
No files matched your search
@@ -1,46 +1,71 @@
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
- "v*"
|
||||
|
||||
concurrency:
|
||||
group: release-${{ gitea.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
env:
|
||||
RUNNER_TOOL_CACHE: /toolcache
|
||||
PLATFORMIO_BUILD_CACHE_DIR: ~/.platformio/.build_cache
|
||||
PLATFORMIO_CACHE_DIR: ~/.platformio/.cachedir
|
||||
name: Build
|
||||
name: Build ${{ matrix.environment }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
environment:
|
||||
- heltec_wifi_lora_32_V3_sailplane
|
||||
- heltec_wifi_lora_32_V3_winde
|
||||
runs-on: ubuntu-latest
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
~/.platformio/.cache
|
||||
~/.platformio/.build_cache
|
||||
~/.platformio/.cachedir
|
||||
key: ${{ runner.os }}-pio
|
||||
key: ${{ runner.os }}-pio-6.1.18-${{ hashFiles('platformio.ini', 'extra_script.py') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pio-6.1.18-
|
||||
${{ runner.os }}-pio-
|
||||
- name: Set up python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version: "3.14.0"
|
||||
architecture: "x64"
|
||||
- name: Install PlatformIO
|
||||
run: python3 -m pip install platformio==6.1.18
|
||||
- name: Build firmwares
|
||||
run: FIRMWARE_VERSION=${{gitea.ref_name}} platformio run
|
||||
- name: Archive
|
||||
uses: christopherhx/gitea-upload-artifact@v4
|
||||
- name: Static analysis
|
||||
run: python3 -m platformio check --environment "${{ matrix.environment }}"
|
||||
- name: Build firmware
|
||||
env:
|
||||
FIRMWARE_VERSION: ${{ gitea.ref_name }}
|
||||
run: python3 -m platformio run --environment "${{ matrix.environment }}"
|
||||
- name: Verify firmware and create checksum
|
||||
run: |
|
||||
FIRMWARE_FILE=$(find ".pio/build/${{ matrix.environment }}" -maxdepth 1 -type f -name 'firmware_*.bin' -print -quit)
|
||||
test -n "$FIRMWARE_FILE"
|
||||
sha256sum "$FIRMWARE_FILE" > "firmware-${{ matrix.environment }}.sha256"
|
||||
- name: Archive firmware
|
||||
uses: christopherhx/gitea-upload-artifact@62ac910c5d3dfa85c7cb2df15afe2e342b2407c2 # v4
|
||||
with:
|
||||
name: firmware
|
||||
path: .pio/build/*/firmware_*.bin
|
||||
name: firmware-${{ matrix.environment }}
|
||||
path: |
|
||||
.pio/build/${{ matrix.environment }}/firmware_*.bin
|
||||
firmware-${{ matrix.environment }}.sha256
|
||||
retention-days: 1
|
||||
release:
|
||||
name: Release
|
||||
# if: startsWith(github.event.ref, 'refs/tags/v')
|
||||
if: startsWith(gitea.ref, 'refs/tags/v')
|
||||
needs: build
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -48,17 +73,29 @@ jobs:
|
||||
container: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
- name: Checkout repo for CHANGELOG
|
||||
uses: actions/checkout@v4
|
||||
- name: Download artifacts
|
||||
uses: christopherhx/gitea-download-artifact@v4
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- name: Download Sailplane artifact
|
||||
uses: christopherhx/gitea-download-artifact@75635f32b4c1c41c4b3d64e8f85210112ed4c9c7 # v4
|
||||
with:
|
||||
name: firmware
|
||||
path: firmware
|
||||
# - name: Display structure of downloaded files
|
||||
# run: ls -R
|
||||
- name: release
|
||||
uses: akkuman/gitea-release-action@v1
|
||||
name: firmware-heltec_wifi_lora_32_V3_sailplane
|
||||
path: firmware/sailplane
|
||||
- name: Download Winde artifact
|
||||
uses: christopherhx/gitea-download-artifact@75635f32b4c1c41c4b3d64e8f85210112ed4c9c7 # v4
|
||||
with:
|
||||
name: firmware-heltec_wifi_lora_32_V3_winde
|
||||
path: firmware/winde
|
||||
- name: Verify release assets
|
||||
run: |
|
||||
test -n "$(find firmware -type f -name 'firmware_*.bin' -print -quit)"
|
||||
test -n "$(find firmware -type f -name '*.sha256' -print -quit)"
|
||||
test -s LICENSE
|
||||
test -s THIRD_PARTY_NOTICES.md
|
||||
- name: Create release
|
||||
uses: akkuman/gitea-release-action@5a83c90484ef4355121df5eb60558c8ce66e81ac # v1
|
||||
with:
|
||||
files: |-
|
||||
**/firmware_*.bin
|
||||
firmware/**/*.bin
|
||||
firmware/**/*.sha256
|
||||
LICENSE
|
||||
THIRD_PARTY_NOTICES.md
|
||||
body_path: "CHANGELOG.md"
|
||||
+37
-1
@@ -1,6 +1,42 @@
|
||||
CHANGELOG
|
||||
## v0.0.7c (28.08.2026)
|
||||
+ korrektur AutoBuild (Checksum)
|
||||
|
||||
## 0.0.5 (30.11.2025)
|
||||
## v0.0.7b (28.08.2026)
|
||||
+ korrektur AutoBuild
|
||||
|
||||
## v0.0.7a (28.08.2026)
|
||||
+ verbessertes AutoBuild
|
||||
|
||||
## v0.0.7 (28.08.2026)
|
||||
+ Webinterface über eigenen WLAN-Access-Point ergänzt
|
||||
+ Persistente Konfiguration für WLAN-Name, WLAN-Passwort und Callsign
|
||||
+ Lizenzinformationen für Projektcode und Drittanbieterbibliotheken ergänzt
|
||||
+ Firmware-Upload über das Webinterface für beide Firmwarevarianten ergänzt
|
||||
|
||||
### Segeflug Modul
|
||||
+ Einstellbare minimale und maximale Schleppgeschwindigkeit
|
||||
+ Einstellbare maximale Übertragungszeit, Standardwert 90 Sekunden
|
||||
+ Geladene Einstellungen beim Programmstart verwendet
|
||||
+ Sensorinitialisierung und Messwertverarbeitung robustifiziert
|
||||
|
||||
### Winden Modul
|
||||
+ Einstellbare WLAN-Konfiguration über das Webinterface
|
||||
+ Standard-WLAN-Name `Winde-Telemetry`
|
||||
+ Initialisierung von Servo und LED-Ring korrigiert
|
||||
+ NMEA-Nachrichtenprüfung und Fehlerbehandlung beim Empfang verbessert
|
||||
|
||||
## v0.0.6 (18.01.2026)
|
||||
+ Anpassung Programmablaufplan
|
||||
|
||||
### Segeflug Modul
|
||||
+ Umsetzen der Sender-Logik
|
||||
+ senden im NMEA Format
|
||||
|
||||
### Winden Modul
|
||||
+ empfangen im NMEA Format
|
||||
|
||||
## v0.0.5 (30.11.2025)
|
||||
+ Formatierung Code
|
||||
### Segeflug Modul
|
||||
+ Luftdrucksensor (BMP180) hinzugefügt, für Höhe und Vario
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Winden-Telemetry contributors
|
||||
|
||||
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.
|
||||
@@ -1,7 +1,15 @@
|
||||
[](https://gitea.rabe11.de/FCS/Winden-Telemetry/releases)
|
||||

|
||||
|
||||
|
||||
# Winden-Telemetry
|
||||
|
||||
Der eigene Projektcode steht unter der MIT-Lizenz. Die verwendeten
|
||||
Drittanbieterbibliotheken bleiben unter ihren jeweiligen Original-Lizenzen.
|
||||
Eine Übersicht der Komponenten, Versionen und Lizenzbedingungen steht in
|
||||
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md); der vollständige Lizenztext
|
||||
für den Projektcode steht in [LICENSE](LICENSE).
|
||||
|
||||
|
||||
Übertragung der IAS des Segelflugzeuges an die Winde
|
||||
|
||||
@@ -17,16 +25,37 @@
|
||||
### Features:
|
||||
- [x] LORA zum Übertragen
|
||||
- [x] Airspeed via differenz Drucksensor
|
||||
- [ ] Webinterface
|
||||
- [ ] min/max speed einstellbar
|
||||
- [ ] Kennzeichen einstellbar
|
||||
- [x] Webinterface über eigenen Access Point
|
||||
- [x] min/max speed per Webinterface einstellbar
|
||||
- [x] Kennzeichen per Webinterface einstellbar
|
||||
- [x] maximale Übertragungszeit per Webinterface einstellbar (Standard: 90 Sekunden)
|
||||
- [x] Firmware-Upload per Webinterface für beide Firmwarevarianten
|
||||
- [x] Analoge Anzeige in der Winde
|
||||
- [x] Farbige LEDs für Limits
|
||||
- [ ] Übertragungszeit Begrenzen
|
||||
- [ ] Übertragungszeit einstellbar
|
||||
- [x] Übertragungszeit Begrenzen
|
||||
- [ ] Übertragung Rundumleuchten Signal an Start
|
||||
- [x] Luftdrucksensor für Höhe und Vario
|
||||
|
||||
### Webinterface und Firmware-Update
|
||||
|
||||
Beide Firmwarevarianten starten einen eigenen WLAN-Access-Point. Der
|
||||
voreingestellte WLAN-Name ist bei Sailplane `Sailplane-D1234` und bei der
|
||||
Winde `Winde-Telemetry`.
|
||||
|
||||
- Passwort: `telemetry`
|
||||
- Webadresse: `http://192.168.4.1/`
|
||||
|
||||
Im Webinterface können WLAN-Name und WLAN-Passwort sowie Callsign, minimale und maximale Geschwindigkeit
|
||||
gespeichert werden. Die Werte bleiben nach einem Neustart erhalten. Die
|
||||
Sailplane-Firmware lädt sie beim Start und verwendet sie für die Telemetrie,
|
||||
die Schlepp-Erkennung und die maximale Übertragungszeit. Die Winden-Firmware verwendet die gespeicherten
|
||||
Grenzen für die Anzeige beim Start; empfangene Telemetriegrenzen werden danach
|
||||
weiterhin aus dem LoRa-Paket übernommen.
|
||||
|
||||
Für ein Firmware-Update die zur jeweiligen Hardware passende `.bin`-Datei aus
|
||||
`.pio/build/<environment>/` auswählen. Nach erfolgreichem Upload startet das
|
||||
Gerät automatisch neu.
|
||||
|
||||
## Aufbau
|
||||
|
||||
Pin Layout Heltec WiFi LoRa (v3)
|
||||
@@ -44,3 +73,59 @@ Pin Layout Heltec WiFi LoRa (v3)
|
||||
| GPIO19| | | SDA| SDA |
|
||||
| GPIO20| | | SCL| SCL|
|
||||
| 5V | OUT + | VCC | | |
|
||||
|
||||
|
||||
|
||||
## PCB
|
||||
Die Platine ist so gestaltet das sie individuell bestückt werden kann, je nach Verwendung
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
[Schaltplan](img/Winden_Telemetry_Schematic.pdf)
|
||||
|
||||
| Bauteil | Modul Segelflugzeug | Modul Winde | Modul SKP |
|
||||
| --- |--- |--- |--- |
|
||||
| J1 | x | x | x | optional|
|
||||
| A1 | x | x | x | optional|
|
||||
| I2C_1 | MS4525 | optional| optional|
|
||||
| I2C_2 | BMP180 | optional| optional|
|
||||
| I2C_3 | optional| optional| optional|
|
||||
| I2C_4 | optional| optional| optional|
|
||||
| GPIO3 | optional| optional| optional|
|
||||
| GPIO4 | optional| optional| optional|
|
||||
| GPIO5 | optional| Eingang Warnleuchte |optional|
|
||||
| GPIO6 | optional| LED Ring | optional|
|
||||
| GPIO7 | optional| Servo | für Relais|
|
||||
|
||||
|
||||
|
||||
## Programmablauf Segelflugzeug
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A(["Start"])
|
||||
A --> B{"ist Senden an?"}
|
||||
B --> | Ja | C{"Sende Timer <90 sec"}
|
||||
I --> | Nein | E{"is airborn?"}
|
||||
|
||||
C --> | Nein | F["Sende Schleppen komplett"] -->G["is airborn=true"] -->L["Lowspeedtimer = 0"]
|
||||
C --> | Ja | D["Sende Speed"]
|
||||
|
||||
|
||||
D --> Z["Warte 1 Sekunde"]
|
||||
L ----> H["Senden aus"] -->Z
|
||||
|
||||
Z --> B
|
||||
|
||||
B --> | nein | I{"Speed < 30 km/h"}
|
||||
E --> | nein |J["Senden an"] -->P["Start Sendetimer"] --> D
|
||||
I --> | ja| K["Lowspeedtimer + 1"]
|
||||
K --> M{"lowspeedtimer >90"}
|
||||
M --> | ja | N["is airborn=false"] --> Z
|
||||
M --> | nein | Z
|
||||
E --> | ja |O["Lowspeedtimer = 0"] --> Z
|
||||
|
||||
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
# Third-party notices
|
||||
|
||||
This project contains or links to the following third-party software. The
|
||||
listed versions are the versions resolved by PlatformIO on 2026-08-28.
|
||||
Original license texts and copyright notices must be retained when the
|
||||
corresponding software is redistributed.
|
||||
|
||||
## Direct and transitive library dependencies
|
||||
|
||||
| Component | Version | Used by | License | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| U8g2 | 2.36.18 | Sailplane, Winde | BSD-2-Clause; bundled fonts may have additional licenses | https://github.com/olikraus/u8g2 |
|
||||
| RadioLib | 7.6.0 | Sailplane, Winde | MIT | https://github.com/jgromes/RadioLib |
|
||||
| ArduinoJson | 7.4.3 | Sailplane, Winde | MIT | https://github.com/bblanchon/ArduinoJson |
|
||||
| Bolder Flight Systems Airdata Calculations | 4.0.0 | Sailplane | MIT | https://github.com/bolderflight/airdata_calculations |
|
||||
| Bolder Flight Systems MS4525 | 1.1.3 | Sailplane | MIT | https://github.com/bolderflight/ms4525 |
|
||||
| Bolder Flight Systems Unit Conversions | 5.0.0 | Sailplane | MIT | https://github.com/bolderflight/units |
|
||||
| Adafruit BMP085 Library | 1.2.4 | Sailplane | BSD | https://github.com/adafruit/Adafruit-BMP085-Library |
|
||||
| Adafruit BusIO | 1.17.4 | Sailplane, transitive | MIT | https://github.com/adafruit/Adafruit_BusIO |
|
||||
| Adafruit Unified Sensor | 1.1.15 | Sailplane, transitive | Apache-2.0 | https://github.com/adafruit/Adafruit_Sensor |
|
||||
| Adafruit NeoPixel | 1.15.4 | Winde | LGPL-3.0-or-later | https://github.com/adafruit/Adafruit_NeoPixel |
|
||||
| ESP32Servo | 3.1.3 | Winde | LGPL-2.1-or-later | https://github.com/madhephaestos/ESP32Servo |
|
||||
|
||||
## Build framework
|
||||
|
||||
| Component | Version | License | Source |
|
||||
| --- | --- | --- | --- |
|
||||
| Arduino core for ESP32 | 3.20017.241212+sha.dcc1105b | LGPL-2.1-or-later | https://github.com/espressif/arduino-esp32 |
|
||||
|
||||
The PlatformIO platform and build tools are development dependencies. Their
|
||||
licenses are distributed with their respective PlatformIO packages and are
|
||||
not relicensed by this project.
|
||||
|
||||
## License compatibility
|
||||
|
||||
The source code in this repository is licensed under the MIT License in
|
||||
`LICENSE`. MIT is compatible with the MIT, BSD, Apache-2.0 and LGPL components
|
||||
listed above. The LGPL components remain under their original licenses; this
|
||||
project does not change or relicense them.
|
||||
|
||||
For a release containing compiled firmware, distribute this file together
|
||||
with `LICENSE` and retain the copyright and license notices supplied by the
|
||||
third-party components. U8g2 fonts must be checked separately when changing
|
||||
fonts, because their licensing terms can differ from the U8g2 library code.
|
||||
@@ -6,3 +6,9 @@ build_tag = env['PIOENV']
|
||||
version_tag = os.getenv("FIRMWARE_VERSION")
|
||||
|
||||
env.Replace(PROGNAME="firmware_%s_%s" % (build_tag, version_tag))
|
||||
|
||||
# include toolchain paths
|
||||
env.Replace(COMPILATIONDB_INCLUDE_TOOLCHAIN=True)
|
||||
|
||||
# override compilation DB path
|
||||
env.Replace(COMPILATIONDB_PATH=os.path.join("$BUILD_DIR", "compile_commands.json"))
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 485 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
+39
-14
@@ -11,12 +11,19 @@ bfs::Ms4525do pres;
|
||||
Adafruit_BMP085 bmp;
|
||||
|
||||
float pressure_avg[10];
|
||||
float basicaltitude;
|
||||
void init_2ndi2c(){
|
||||
Wire1.begin(dp_sda, dp_scl);
|
||||
float basicaltitude = 0.0f;
|
||||
bool pressure_sensor_ready = false;
|
||||
|
||||
bool init_2ndi2c(){
|
||||
if (!Wire1.begin(dp_sda, dp_scl))
|
||||
{
|
||||
Serial.println("Error starting I2C");
|
||||
return false;
|
||||
}
|
||||
Wire1.setClock(400000);
|
||||
return true;
|
||||
}
|
||||
void init_airspeed_sensor(void)
|
||||
bool init_airspeed_sensor(void)
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -27,10 +34,9 @@ void init_airspeed_sensor(void)
|
||||
if (!pres.Begin())
|
||||
{
|
||||
Serial.println("Error communicating with sensor");
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int get_airspeed_kmh(void)
|
||||
@@ -51,10 +57,22 @@ float get_airspeed(void)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
void init_pressure_sensor(void)
|
||||
bool init_pressure_sensor(void)
|
||||
{
|
||||
bmp.begin(BMP085_ULTRAHIGHRES, &Wire1);
|
||||
if (!bmp.begin(BMP085_ULTRAHIGHRES, &Wire1))
|
||||
{
|
||||
Serial.println("Error communicating with pressure sensor");
|
||||
return false;
|
||||
}
|
||||
basicaltitude=bmp.readPressure();
|
||||
if (basicaltitude <= 0.0f)
|
||||
{
|
||||
Serial.println("Invalid initial pressure");
|
||||
return false;
|
||||
}
|
||||
for (float &sample : pressure_avg)
|
||||
sample = basicaltitude;
|
||||
pressure_sensor_ready = true;
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(basicaltitude);
|
||||
Serial.println(" Pa");
|
||||
@@ -64,21 +82,28 @@ void init_pressure_sensor(void)
|
||||
Serial.print("Altitude = ");
|
||||
Serial.print(get_altitude(basicaltitude));
|
||||
Serial.println(" meters");
|
||||
return true;
|
||||
}
|
||||
|
||||
float get_pressure()
|
||||
{
|
||||
if (!pressure_sensor_ready)
|
||||
return 0.0f;
|
||||
|
||||
float pressure;
|
||||
pressure = bmp.readPressure();
|
||||
memcpy(pressure_avg, &pressure_avg[1], sizeof(pressure_avg) - sizeof(int));
|
||||
if (pressure <= 0.0f)
|
||||
return pressure_avg[9];
|
||||
|
||||
memmove(pressure_avg, &pressure_avg[1], sizeof(pressure_avg) - sizeof(pressure_avg[0]));
|
||||
pressure_avg[9] = pressure;
|
||||
return pressure;
|
||||
}
|
||||
|
||||
float get_pressure_avg(void)
|
||||
{
|
||||
float total = 0.0f;
|
||||
int i;
|
||||
float total;
|
||||
for (i = 0; i <10; i++)
|
||||
{
|
||||
total = total + pressure_avg[i];
|
||||
@@ -97,14 +122,14 @@ float get_vario_avg(void)
|
||||
float vario;
|
||||
|
||||
int i;
|
||||
float total;
|
||||
float total = 0.0f;
|
||||
for (i = 0; i <9; i++)
|
||||
{
|
||||
int n=i+1;
|
||||
vario = get_altitude(pressure_avg[n]) - get_altitude(pressure_avg[i]);
|
||||
total = total + vario;
|
||||
}
|
||||
return (total / 10);
|
||||
return (total / 9);
|
||||
}
|
||||
|
||||
float get_altitude(float pressure)
|
||||
@@ -115,5 +140,5 @@ float get_altitude(float pressure)
|
||||
}
|
||||
|
||||
float get_altitude_diff(void){
|
||||
return bmp.readPressure() - basicaltitude;
|
||||
return get_altitude(pressure_avg[9]) - get_altitude(basicaltitude);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef WINDENTELEMETRY_AIRSPEED_H
|
||||
#define WINDENTELEMETRY_AIRSPEED_H
|
||||
|
||||
void init_2ndi2c(void);
|
||||
void init_airspeed_sensor(void);
|
||||
bool init_2ndi2c(void);
|
||||
bool init_airspeed_sensor(void);
|
||||
|
||||
int get_airspeed_kmh(void);
|
||||
/*!
|
||||
@@ -10,7 +10,7 @@ int get_airspeed_kmh(void);
|
||||
*/
|
||||
float get_airspeed(void);
|
||||
|
||||
void init_pressure_sensor(void);
|
||||
bool init_pressure_sensor(void);
|
||||
float get_pressure(void);
|
||||
float get_pressure_adv(void);
|
||||
float get_altitude(float pressure);
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
#include "webinterface.h"
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#include <Update.h>
|
||||
#include <WebServer.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr char default_access_point_password[] = "telemetry";
|
||||
constexpr char settings_namespace[] = "telemetry";
|
||||
constexpr char default_callsign[] = "D1234";
|
||||
constexpr int default_min_speed = 80;
|
||||
constexpr int default_max_speed = 150;
|
||||
constexpr unsigned int default_active_time_seconds = 90;
|
||||
|
||||
String default_access_point_name()
|
||||
{
|
||||
#ifdef DEVICE_SAILPLANE
|
||||
return String("Sailplane-") + default_callsign;
|
||||
#else
|
||||
return "Winde-Telemetry";
|
||||
#endif
|
||||
}
|
||||
|
||||
WebServer server(80);
|
||||
Preferences preferences;
|
||||
TelemetrySettings *active_settings = nullptr;
|
||||
bool restart_after_update = false;
|
||||
bool update_failed = false;
|
||||
bool access_point_restart_pending = false;
|
||||
|
||||
String html_escape(const String &value)
|
||||
{
|
||||
String escaped = value;
|
||||
escaped.replace("&", "&");
|
||||
escaped.replace("<", "<");
|
||||
escaped.replace(">", ">");
|
||||
escaped.replace("\"", """);
|
||||
escaped.replace("'", "'");
|
||||
return escaped;
|
||||
}
|
||||
|
||||
void send_page(const String &message = String())
|
||||
{
|
||||
String page;
|
||||
page.reserve(2600);
|
||||
page += F("<!doctype html><html lang='de'><head><meta charset='utf-8'>"
|
||||
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
|
||||
"<title>Winden-Telemetry</title><style>"
|
||||
"body{font-family:sans-serif;max-width:38rem;margin:2rem auto;padding:0 1rem}"
|
||||
"label{display:block;margin-top:1rem}input{box-sizing:border-box;width:100%;padding:.6rem;font-size:1rem}"
|
||||
"button{margin-top:1rem;padding:.65rem 1rem;font-size:1rem}"
|
||||
".msg{padding:.6rem;background:#e5f4e8}small{color:#555}"
|
||||
"</style></head><body><h1>Winden-Telemetry</h1>");
|
||||
if (message.length() > 0)
|
||||
{
|
||||
page += F("<p class='msg'>");
|
||||
page += html_escape(message);
|
||||
page += F("</p>");
|
||||
}
|
||||
page += F("<form method='post' action='/settings'>"
|
||||
"<label>WLAN-Name<input name='ap_name' maxlength='32' required value='");
|
||||
page += html_escape(active_settings->access_point_name);
|
||||
page += F("'></label><label>WLAN-Passwort<input name='ap_password' type='password' minlength='8' maxlength='63' required value='");
|
||||
page += html_escape(active_settings->access_point_password);
|
||||
page += F("'></label><label>Callsign<input name='callsign' maxlength='16' required value='");
|
||||
page += html_escape(active_settings->callsign);
|
||||
page += F("'></label><label>Min Speed (km/h)<input name='min' type='number' min='0' max='300' required value='");
|
||||
page += String(active_settings->min_speed);
|
||||
page += F("'></label><label>Max Speed (km/h)<input name='max' type='number' min='1' max='300' required value='");
|
||||
page += String(active_settings->max_speed);
|
||||
page += F("'></label><label>Uebertragungszeit (Sekunden)<input name='active_time' type='number' min='1' max='600' required value='");
|
||||
page += String(active_settings->active_time_seconds);
|
||||
page += F("'></label><button type='submit'>Speichern</button></form>"
|
||||
"<h2>Firmware aktualisieren</h2><form method='post' action='/update' enctype='multipart/form-data'>"
|
||||
"<input name='firmware' type='file' accept='.bin' required><button type='submit'>Upload starten</button>"
|
||||
"</form><p><small>Access Point: ");
|
||||
page += html_escape(active_settings->access_point_name);
|
||||
page += F("</small></p></body></html>");
|
||||
server.send(200, "text/html; charset=utf-8", page);
|
||||
}
|
||||
|
||||
bool parse_settings(TelemetrySettings &settings)
|
||||
{
|
||||
String callsign = server.arg("callsign");
|
||||
String access_point_name = server.arg("ap_name");
|
||||
String access_point_password = server.arg("ap_password");
|
||||
int min_speed = server.arg("min").toInt();
|
||||
int max_speed = server.arg("max").toInt();
|
||||
int active_time_seconds = server.arg("active_time").toInt();
|
||||
callsign.trim();
|
||||
access_point_name.trim();
|
||||
access_point_password.trim();
|
||||
if (access_point_name.length() == 0 || access_point_name.length() > 32 || access_point_password.length() < 8 || access_point_password.length() > 63 || callsign.length() == 0 || callsign.length() > 16 || min_speed < 0 || max_speed > 300 ||
|
||||
min_speed >= max_speed || active_time_seconds < 1 || active_time_seconds > 600)
|
||||
return false;
|
||||
|
||||
settings.callsign = callsign;
|
||||
settings.access_point_name = access_point_name;
|
||||
settings.access_point_password = access_point_password;
|
||||
settings.min_speed = min_speed;
|
||||
settings.max_speed = max_speed;
|
||||
settings.active_time_seconds = active_time_seconds;
|
||||
return true;
|
||||
}
|
||||
|
||||
void handle_root()
|
||||
{
|
||||
send_page();
|
||||
}
|
||||
|
||||
void handle_settings()
|
||||
{
|
||||
TelemetrySettings updated = *active_settings;
|
||||
if (!parse_settings(updated))
|
||||
{
|
||||
server.send(400, "text/plain; charset=utf-8", "Ungueltige Einstellungen");
|
||||
return;
|
||||
}
|
||||
|
||||
active_settings->callsign = updated.callsign;
|
||||
active_settings->access_point_name = updated.access_point_name;
|
||||
active_settings->access_point_password = updated.access_point_password;
|
||||
active_settings->min_speed = updated.min_speed;
|
||||
active_settings->max_speed = updated.max_speed;
|
||||
active_settings->active_time_seconds = updated.active_time_seconds;
|
||||
preferences.putString("callsign", active_settings->callsign);
|
||||
preferences.putString("ap_name", active_settings->access_point_name);
|
||||
preferences.putString("ap_password", active_settings->access_point_password);
|
||||
preferences.putInt("min", active_settings->min_speed);
|
||||
preferences.putInt("max", active_settings->max_speed);
|
||||
preferences.putUInt("active_time", active_settings->active_time_seconds);
|
||||
send_page("Einstellungen gespeichert.");
|
||||
access_point_restart_pending = true;
|
||||
}
|
||||
|
||||
void handle_update_upload()
|
||||
{
|
||||
HTTPUpload &upload = server.upload();
|
||||
if (upload.status == UPLOAD_FILE_START)
|
||||
{
|
||||
restart_after_update = false;
|
||||
update_failed = false;
|
||||
Serial.printf("Firmware-Upload: %s\n", upload.filename.c_str());
|
||||
if (!Update.begin(UPDATE_SIZE_UNKNOWN))
|
||||
{
|
||||
update_failed = true;
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
else if (upload.status == UPLOAD_FILE_WRITE)
|
||||
{
|
||||
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize)
|
||||
{
|
||||
update_failed = true;
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
else if (upload.status == UPLOAD_FILE_END)
|
||||
{
|
||||
if (Update.end(true))
|
||||
{
|
||||
restart_after_update = true;
|
||||
Serial.printf("Firmware-Upload abgeschlossen: %u Bytes\n", upload.totalSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_failed = true;
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_update_result()
|
||||
{
|
||||
if (!update_failed && restart_after_update)
|
||||
{
|
||||
server.send(200, "text/plain; charset=utf-8", "Upload erfolgreich. Neustart...");
|
||||
if (restart_after_update)
|
||||
{
|
||||
delay(500);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
else
|
||||
server.send(500, "text/plain; charset=utf-8", "Firmware-Upload fehlgeschlagen");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool webinterface_begin(TelemetrySettings &settings)
|
||||
{
|
||||
active_settings = &settings;
|
||||
preferences.begin(settings_namespace, false);
|
||||
settings.callsign = preferences.getString("callsign", default_callsign);
|
||||
settings.access_point_name = preferences.getString("ap_name", default_access_point_name());
|
||||
settings.access_point_password = preferences.getString("ap_password", default_access_point_password);
|
||||
settings.min_speed = preferences.getInt("min", default_min_speed);
|
||||
settings.max_speed = preferences.getInt("max", default_max_speed);
|
||||
settings.active_time_seconds = preferences.getUInt("active_time", default_active_time_seconds);
|
||||
if (settings.access_point_name.length() == 0 || settings.access_point_name.length() > 32 || settings.access_point_password.length() < 8 || settings.access_point_password.length() > 63 || settings.callsign.length() == 0 || settings.min_speed < 0 || settings.min_speed >= settings.max_speed ||
|
||||
settings.max_speed > 300 || settings.active_time_seconds < 1 || settings.active_time_seconds > 600)
|
||||
{
|
||||
settings.callsign = default_callsign;
|
||||
settings.access_point_name = default_access_point_name();
|
||||
settings.access_point_password = default_access_point_password;
|
||||
settings.min_speed = default_min_speed;
|
||||
settings.max_speed = default_max_speed;
|
||||
settings.active_time_seconds = default_active_time_seconds;
|
||||
}
|
||||
|
||||
WiFi.mode(WIFI_AP);
|
||||
bool ap_started = WiFi.softAP(settings.access_point_name, settings.access_point_password);
|
||||
if (!ap_started)
|
||||
return false;
|
||||
|
||||
server.on("/", HTTP_GET, handle_root);
|
||||
server.on("/settings", HTTP_POST, handle_settings);
|
||||
server.on("/update", HTTP_POST, handle_update_result, handle_update_upload);
|
||||
server.begin();
|
||||
Serial.print("Webinterface: http://");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
return true;
|
||||
}
|
||||
|
||||
void webinterface_handle(void)
|
||||
{
|
||||
server.handleClient();
|
||||
if (access_point_restart_pending)
|
||||
{
|
||||
access_point_restart_pending = false;
|
||||
WiFi.softAPdisconnect(true);
|
||||
delay(100);
|
||||
if (!WiFi.softAP(active_settings->access_point_name, active_settings->access_point_password))
|
||||
Serial.println("Access Point konnte nicht neu gestartet werden");
|
||||
}
|
||||
}
|
||||
|
||||
const TelemetrySettings &webinterface_settings(void)
|
||||
{
|
||||
return *active_settings;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef WINDENTELEMETRY_WEBINTERFACE_H
|
||||
#define WINDENTELEMETRY_WEBINTERFACE_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
struct TelemetrySettings
|
||||
{
|
||||
String callsign;
|
||||
String access_point_name;
|
||||
String access_point_password;
|
||||
int min_speed;
|
||||
int max_speed;
|
||||
unsigned int active_time_seconds;
|
||||
};
|
||||
|
||||
bool webinterface_begin(TelemetrySettings &settings);
|
||||
void webinterface_handle(void);
|
||||
const TelemetrySettings &webinterface_settings(void);
|
||||
|
||||
#endif
|
||||
+3
-10
@@ -8,15 +8,14 @@ void init_servo(void)
|
||||
{
|
||||
myservo.setPeriodHertz(50);
|
||||
myservo.attach(servoPin);
|
||||
set_tacho(0, 70, 150);
|
||||
}
|
||||
|
||||
void set_tacho(int speed, int speed_min, int speed_max)
|
||||
{
|
||||
int val = map(speed, -25, 220, 0, 155);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Tacho Mapping: ")
|
||||
Serial.println(val);
|
||||
Serial.print("Tacho Mapping: ");
|
||||
Serial.println(val);
|
||||
#endif
|
||||
myservo.write(val);
|
||||
pixels.clear();
|
||||
@@ -72,11 +71,5 @@ void init_pixel(void)
|
||||
|
||||
int setoffsetpixel(int pixel)
|
||||
{
|
||||
int newpixel;
|
||||
newpixel = pixel + pixeloffset;
|
||||
if (newpixel >= NUMPIXELS)
|
||||
{
|
||||
newpixel = newpixel - NUMPIXELS;
|
||||
}
|
||||
return newpixel;
|
||||
return (pixel + pixeloffset + NUMPIXELS) % NUMPIXELS;
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
#define WINDENTELEMETRY_CONFIG_H
|
||||
|
||||
#define LORA_FREQ 868.0
|
||||
#define TELEMETRY_CALLSIGN "D1234"
|
||||
#define TELEMETRY_SEND_INTERVAL_MS 1000UL
|
||||
#define TELEMETRY_ACTIVE_TIME_MS 90000UL
|
||||
#define TELEMETRY_LOW_SPEED_KMH 30
|
||||
#define default_min_tow_speed 80
|
||||
#define default_max_tow_speed 150
|
||||
#ifdef HELTEC_WIFI_LORA_32_V3
|
||||
// SX1262 on HELTEC_WIFI_LORA_32_V3 has the following connections:
|
||||
// NSS pin: 8
|
||||
@@ -27,8 +33,6 @@
|
||||
/**difference pressure**/
|
||||
#define dp_scl 20
|
||||
#define dp_sda 19
|
||||
#define default_min_tow_speed 80
|
||||
#define default_max_tow_speed 150
|
||||
#endif
|
||||
|
||||
#ifdef DEVICE_WINDE
|
||||
|
||||
+11
-8
@@ -9,8 +9,8 @@
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[platformio]
|
||||
build_cache_dir = ./.pio/.build_cache
|
||||
cache_dir = ./.pio/.cache_dir
|
||||
build_cache_dir = ~/.pio/.build_cache
|
||||
cache_dir = ~/.pio/.cache_dir
|
||||
|
||||
[common]
|
||||
platform = espressif32
|
||||
@@ -25,6 +25,8 @@ build_flags =
|
||||
-D CORE_DEBUG_LEVEL=5
|
||||
-D SLOW_CLK_TPYE=0
|
||||
-D REGION_EU868
|
||||
-Ilib
|
||||
-Isrc
|
||||
lib_deps =
|
||||
olikraus/U8g2@^2.36.15
|
||||
jgromes/RadioLib@^7.4.0
|
||||
@@ -41,12 +43,13 @@ lib_deps =
|
||||
bolderflight/Bolder Flight Systems Unit Conversions@^5.0.0
|
||||
bolderflight/Bolder Flight Systems Airdata Calculations@^4.0.0
|
||||
adafruit/Adafruit BMP085 Library @ ^1.2.4
|
||||
lib_ignore =
|
||||
winde
|
||||
build_flags = ${common.build_flags}
|
||||
lib_ignore = winde
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-D DEVICE_SAILPLANE
|
||||
upload_port = COM8
|
||||
monitor_port = COM8
|
||||
|
||||
[env:heltec_wifi_lora_32_V3_winde]
|
||||
extends = common
|
||||
board = heltec_wifi_lora_32_V3
|
||||
@@ -54,9 +57,9 @@ lib_deps =
|
||||
${common.lib_deps}
|
||||
adafruit/Adafruit NeoPixel@^1.15.2
|
||||
madhephaestus/ESP32Servo@^3.0.9
|
||||
lib_ignore =
|
||||
sailplane
|
||||
build_flags = ${common.build_flags}
|
||||
lib_ignore = sailplane
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-D DEVICE_WINDE
|
||||
upload_port = COM9
|
||||
monitor_port = COM9
|
||||
+242
-80
@@ -3,24 +3,27 @@
|
||||
#include <U8g2lib.h>
|
||||
#include <RadioLib.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <webinterface.h>
|
||||
#ifdef DEVICE_WINDE
|
||||
#include <tacho.h>
|
||||
#endif
|
||||
|
||||
TelemetrySettings telemetry_settings;
|
||||
|
||||
#ifdef DEVICE_SAILPLANE
|
||||
#include <airspeed.h>
|
||||
JsonDocument sailplane_data;
|
||||
unsigned long previousMillisSend = 0;
|
||||
unsigned long previousMillissendtimer = 0;
|
||||
bool send_data = false;
|
||||
bool is_airborn = false;
|
||||
unsigned long lowspeedtimer = 0;
|
||||
bool sensors_ready = false;
|
||||
#endif
|
||||
|
||||
SX1262 radio = new Module(LORA_NSS, LORA_DIO1, LORA_NRST, LORA_BUSY);
|
||||
|
||||
bool radio_ready = false;
|
||||
#ifdef DEVICE_WINDE
|
||||
volatile bool receivedFlag = false;
|
||||
|
||||
// this function is called when a complete packet
|
||||
// is received by the module
|
||||
// IMPORTANT: this function MUST be 'void' type
|
||||
// and MUST NOT have any arguments!
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
ICACHE_RAM_ATTR
|
||||
#endif
|
||||
@@ -35,61 +38,88 @@ void setFlag(void)
|
||||
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, OLED_RST, OLED_CLK, OLED_DATA);
|
||||
#endif
|
||||
|
||||
#ifdef DEVICE_WINDE
|
||||
|
||||
String data_from;
|
||||
int data_speed = 0;
|
||||
int data_min = 0;
|
||||
int data_max = 0;
|
||||
|
||||
#endif
|
||||
|
||||
void setup()
|
||||
{
|
||||
/* Serial to display data */
|
||||
Serial.begin(115200);
|
||||
Serial.println("start");
|
||||
if (!webinterface_begin(telemetry_settings))
|
||||
Serial.println("Webinterface konnte nicht gestartet werden");
|
||||
int state = radio.begin(LORA_FREQ);
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
{
|
||||
radio_ready = true;
|
||||
Serial.println(F("success!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true)
|
||||
{
|
||||
delay(10);
|
||||
}
|
||||
Serial.println(F("Webinterface bleibt verfuegbar"));
|
||||
}
|
||||
u8g2.begin();
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_ncenB14_tr);
|
||||
#ifdef DEVICE_SAILPLANE
|
||||
u8g2.drawStr(0, 20, "Start Plane");
|
||||
init_2ndi2c();
|
||||
init_airspeed_sensor();
|
||||
init_pressure_sensor();
|
||||
sensors_ready = init_2ndi2c() && init_airspeed_sensor() && init_pressure_sensor();
|
||||
if (!sensors_ready)
|
||||
{
|
||||
u8g2.drawStr(0, 40, "Sensor error");
|
||||
}
|
||||
#endif
|
||||
#ifdef DEVICE_WINDE
|
||||
u8g2.drawStr(0, 20, "Start Winde");
|
||||
init_servo();
|
||||
init_pixel();
|
||||
init_servo();
|
||||
set_tacho(0, telemetry_settings.min_speed, telemetry_settings.max_speed);
|
||||
|
||||
radio.setPacketReceivedAction(setFlag);
|
||||
|
||||
// start listening for LoRa packets
|
||||
|
||||
state = radio.startReceive();
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
if (radio_ready)
|
||||
{
|
||||
Serial.println(F("success!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true)
|
||||
state = radio.startReceive();
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
{
|
||||
delay(10);
|
||||
Serial.println(F("success!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
radio_ready = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
u8g2.sendBuffer();
|
||||
}
|
||||
|
||||
String nmea_checksum(String str)
|
||||
{
|
||||
byte cs = 0;
|
||||
for (unsigned int n = 1; n < str.length(); n++)
|
||||
{
|
||||
if (str[n] == '*')
|
||||
break;
|
||||
cs ^= str[n];
|
||||
}
|
||||
|
||||
if (cs < 0x10)
|
||||
return "*0" + String(cs, HEX);
|
||||
else
|
||||
return "*" + String(cs, HEX);
|
||||
}
|
||||
void draw_rssi(int Rssi){
|
||||
u8g2.drawFrame(102,8,4,3);
|
||||
u8g2.drawFrame(107,6,4,5);
|
||||
@@ -121,53 +151,195 @@ void draw_rssi(int Rssi){
|
||||
|
||||
|
||||
}
|
||||
|
||||
void send_lora(String data)
|
||||
{
|
||||
if (!radio_ready)
|
||||
return;
|
||||
|
||||
int state = radio.transmit(data);
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
{
|
||||
// the packet was successfully transmitted
|
||||
Serial.println(F("success!"));
|
||||
|
||||
// print measured data rate
|
||||
Serial.print(F("[SX1262] Datarate:\t"));
|
||||
//Serial.print(radio.getDataRate());
|
||||
Serial.println(F(" bps"));
|
||||
}
|
||||
else if (state == RADIOLIB_ERR_PACKET_TOO_LONG)
|
||||
{
|
||||
// the supplied packet was longer than 256 bytes
|
||||
Serial.println(F("too long!"));
|
||||
}
|
||||
else if (state == RADIOLIB_ERR_TX_TIMEOUT)
|
||||
{
|
||||
// timeout occured while transmitting packet
|
||||
Serial.println(F("timeout!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
void send_speed(int vel_kmh)
|
||||
{
|
||||
String data;
|
||||
// serializeJson(sailplane_data, data);
|
||||
// sprintf(data,"$PWTLS,%s,%u,%u,%u","D-1234",vel_kmh,70,140);
|
||||
data = "$PWTLS," + telemetry_settings.callsign + "," + String(vel_kmh) + "," + String(telemetry_settings.min_speed) + "," + String(telemetry_settings.max_speed);
|
||||
data += nmea_checksum(data);
|
||||
Serial.println(data);
|
||||
send_lora(data);
|
||||
}
|
||||
|
||||
void send_airborn()
|
||||
{
|
||||
String data;
|
||||
// serializeJson(sailplane_data, data);
|
||||
data = "$PWTLA," + telemetry_settings.callsign + ",1";
|
||||
data += nmea_checksum(data);
|
||||
Serial.println(data);
|
||||
send_lora(data);
|
||||
}
|
||||
String getSplitValue(String data, char separator, int index)
|
||||
{
|
||||
int found = 0;
|
||||
int strIndex[] = {0, -1};
|
||||
int maxIndex = data.length() - 1;
|
||||
for (int i = 0; i <= maxIndex && found <= index; i++)
|
||||
{
|
||||
if (data.charAt(i) == separator || i == maxIndex)
|
||||
{
|
||||
found++;
|
||||
strIndex[0] = strIndex[1] + 1;
|
||||
strIndex[1] = (i == maxIndex) ? i + 1 : i;
|
||||
}
|
||||
}
|
||||
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
|
||||
}
|
||||
#ifdef DEVICE_WINDE
|
||||
|
||||
void decode_start(String data)
|
||||
{
|
||||
data_from = getSplitValue(data, ',', 1);
|
||||
data_speed = (getSplitValue(data, ',', 2)).toInt();
|
||||
data_min = (getSplitValue(data, ',', 3)).toInt();
|
||||
data_max = (getSplitValue(data, ',', 4)).toInt();
|
||||
}
|
||||
void decode_airborn(String data)
|
||||
{
|
||||
data_from = getSplitValue(data, ',', 1);
|
||||
data_speed = 0;
|
||||
data_min = 0;
|
||||
data_max = 0;
|
||||
}
|
||||
|
||||
bool valid_nmea(String data)
|
||||
{
|
||||
int checksum_start = data.indexOf('*');
|
||||
if (checksum_start <= 1 || checksum_start + 2 >= data.length())
|
||||
return false;
|
||||
|
||||
byte checksum = 0;
|
||||
for (int i = 1; i < checksum_start; ++i)
|
||||
checksum ^= data[i];
|
||||
|
||||
String received_checksum = data.substring(checksum_start + 1, checksum_start + 3);
|
||||
received_checksum.toUpperCase();
|
||||
char expected_checksum[3];
|
||||
snprintf(expected_checksum, sizeof(expected_checksum), "%02X", checksum);
|
||||
return received_checksum == expected_checksum;
|
||||
}
|
||||
|
||||
bool decode_msg(String data)
|
||||
{
|
||||
String pos1 = getSplitValue(data, ',', 0);
|
||||
if (pos1 == "$PWTLS")
|
||||
{
|
||||
if (getSplitValue(data, ',', 4).length() == 0)
|
||||
return false;
|
||||
decode_start(data);
|
||||
return true;
|
||||
}
|
||||
else if (pos1 == "$PWTLA")
|
||||
{
|
||||
decode_airborn(data);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Nachricht nicht erkannt");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void loop()
|
||||
{
|
||||
webinterface_handle();
|
||||
#ifdef DEVICE_SAILPLANE
|
||||
|
||||
/* Read the sensor */
|
||||
get_pressure();
|
||||
int vel_kmh = get_airspeed_kmh();
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_logisoso42_tr);
|
||||
u8g2.setCursor(0, 60);
|
||||
u8g2.print(vel_kmh);
|
||||
u8g2.sendBuffer();
|
||||
if (vel_kmh > 30)
|
||||
if (!sensors_ready)
|
||||
{
|
||||
sailplane_data["from"]= "D-1234";
|
||||
sailplane_data["telemetry"]["speed"]=vel_kmh;
|
||||
sailplane_data["telemetry"]["min"]=70;
|
||||
sailplane_data["telemetry"]["max"]=150;
|
||||
String data;
|
||||
serializeJson(sailplane_data,data);
|
||||
//String data = String(vel_kmh);
|
||||
int state = radio.transmit(data);
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
{
|
||||
// the packet was successfully transmitted
|
||||
Serial.println(F("success!"));
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
// print measured data rate
|
||||
Serial.print(F("[SX1262] Datarate:\t"));
|
||||
Serial.print(radio.getDataRate());
|
||||
Serial.println(F(" bps"));
|
||||
}
|
||||
else if (state == RADIOLIB_ERR_PACKET_TOO_LONG)
|
||||
unsigned long currentMillis = millis();
|
||||
unsigned long active_time_ms = telemetry_settings.active_time_seconds * 1000UL;
|
||||
if (currentMillis - previousMillisSend >= TELEMETRY_SEND_INTERVAL_MS)
|
||||
{
|
||||
previousMillisSend = currentMillis;
|
||||
/* Read the sensor */
|
||||
get_pressure();
|
||||
int vel_kmh = get_airspeed_kmh();
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_logisoso42_tr);
|
||||
u8g2.setCursor(0, 60);
|
||||
u8g2.print(vel_kmh);
|
||||
u8g2.sendBuffer();
|
||||
|
||||
if (send_data == false)
|
||||
{
|
||||
// the supplied packet was longer than 256 bytes
|
||||
Serial.println(F("too long!"));
|
||||
}
|
||||
else if (state == RADIOLIB_ERR_TX_TIMEOUT)
|
||||
{
|
||||
// timeout occured while transmitting packet
|
||||
Serial.println(F("timeout!"));
|
||||
if (vel_kmh < telemetry_settings.min_speed)
|
||||
{
|
||||
lowspeedtimer += TELEMETRY_SEND_INTERVAL_MS;
|
||||
if (lowspeedtimer >= active_time_ms)
|
||||
{
|
||||
is_airborn = false;
|
||||
lowspeedtimer = active_time_ms;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_airborn)
|
||||
{
|
||||
lowspeedtimer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_data = true;
|
||||
send_speed(vel_kmh);
|
||||
previousMillissendtimer = currentMillis;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
if (currentMillis - previousMillissendtimer < active_time_ms)
|
||||
{
|
||||
send_speed(vel_kmh);
|
||||
}
|
||||
else
|
||||
{
|
||||
send_airborn();
|
||||
is_airborn = true;
|
||||
lowspeedtimer = 0;
|
||||
send_data = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -176,18 +348,17 @@ void loop()
|
||||
Serial.println(vel_kmh);
|
||||
Serial.print(pres.pres_pa(), 6);
|
||||
Serial.print("IAS (m/s): ");
|
||||
Serial.println(ias);
|
||||
Serial.println(get_airspeed());
|
||||
Serial.println(vel_kmh);
|
||||
Serial.print("\t");
|
||||
Serial.print(pres.die_temp_c(), 6);
|
||||
Serial.print("\n");
|
||||
#endif
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifdef DEVICE_WINDE
|
||||
if (receivedFlag)
|
||||
if (radio_ready && receivedFlag)
|
||||
{
|
||||
// reset flag
|
||||
receivedFlag = false;
|
||||
@@ -195,22 +366,14 @@ void loop()
|
||||
// you can read received data as an Arduino String
|
||||
String str;
|
||||
int state = radio.readData(str);
|
||||
JsonDocument received;
|
||||
deserializeJson(received,str);
|
||||
|
||||
// you can also read received data as byte array
|
||||
/*
|
||||
byte byteArr[8];
|
||||
int numBytes = radio.getPacketLength();
|
||||
int state = radio.readData(byteArr, numBytes);
|
||||
*/
|
||||
|
||||
if (state == RADIOLIB_ERR_NONE)
|
||||
{
|
||||
String data_from=received["from"];
|
||||
int data_speed=received["telemetry"]["speed"];
|
||||
int data_min=received["telemetry"]["min"];
|
||||
int data_max=received["telemetry"]["max"];
|
||||
if (!valid_nmea(str) || !decode_msg(str))
|
||||
{
|
||||
Serial.println("Ungueltige Telemetrie-Nachricht");
|
||||
return;
|
||||
}
|
||||
// packet was successfully received
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_ncenB10_tr);
|
||||
@@ -226,7 +389,6 @@ void loop()
|
||||
draw_rssi(radio.getRSSI());
|
||||
u8g2.sendBuffer();
|
||||
Serial.println(str);
|
||||
int speed = str.toInt();
|
||||
set_tacho(data_speed, data_min, data_max);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user