Files
Constantin LeueandClaude Sonnet 5 46e51b3920 Drohnen-Status-Pille zeigt bei Verbindungsverlust rot/disconnected statt eingefrorener Werte
Waehrend eines Verbindungsverlusts frieren die TelemetryFrame-Werte
bewusst ein (telemetryProvider.value bleibt auf dem letzten Stand, siehe
vorherigen Commit) - die Fusszeilen-Pille im Fly-Modus hat daraus bislang
weiterhin den zuletzt bekannten (ggf. laengst veralteten) Zustand
abgeleitet, statt den Verbindungsverlust selbst widerzuspiegeln.

- domain/telemetry/drone_status.dart: neuer DroneState.disconnected,
  computeDroneStatus() bekommt einen neuen Parameter `connected` - hat
  Vorrang vor allem anderen (auch vor Emergency) und uebersteuert
  connectionQuality auf rot. positionQuality bleibt bewusst unveraendert
  (folgt weiterhin den eingefrorenen Werten) - laut Anfrage sollen nur
  Drohnen-Icon und Verbindungsqualitaet, nicht die Positionsqualitaet, rot
  erzwungen werden.
- fly_screen.dart: `connected: !telemetryAsync.hasError` statt der
  bisherigen Ableitung aus einzelnen Telemetriewerten.
- bottom_stats_bar.dart: neues Label/Farbe ("disconnected", rot) fuer den
  neuen Zustand in der Drohnen-Status-Pille.

Auf dem Pixel_10a-Emulator verifiziert: WiFi-Verbindungsart (noch nie
verbunden) zeigt bereits korrekt rotes Papierflieger-Icon, rote
Verbindungsqualitaet, rotes Satelliten-Icon und "disconnected" in rot;
Mock-Verbindung zeigt unveraendert normal gruen "ready".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 17:38:55 +02:00

110 lines
4.5 KiB
Dart

/// Ampelfarbe fuer die Verbindungs- und Positionsqualitaets-Icons in der
/// Drohnen-Status-Pille (Doku: "icon mit Farbcodierung (gruen/gelb/rot)").
enum SignalLevel { green, yellow, red }
/// Zustand der Drohne fuer das Papierflieger-Icon in der Drohnen-Status-
/// Pille (Doku: "drone state: papierflieger icon mit farbcodierung ... mit
/// text wie (idle, ready, armed, waypoint, error)"). [disconnected] deckt
/// den Fall ab, dass der Telemetrie-Strom selbst gerade fehlerhaft ist
/// (Doku: "Statuspille ... muss eine rote Drohne, eine rote
/// Verbindungsqualität und den Status text in rot disconnected anzeigen"),
/// im Unterschied zu den anderen Zustaenden, die aus (ggf. eingefrorenen,
/// siehe computeDroneStatus) Telemetriewerten abgeleitet werden.
enum DroneState { idle, ready, armed, waypoint, disconnected, error }
/// Kombiniertes Ergebnis aus [computeDroneStatus] - die drei Elemente der
/// Fly-Modus-Drohnen-Pille (Doku: "connection quality", "position quality",
/// "drone state").
class DroneStatus {
const DroneStatus({
required this.connectionQuality,
required this.positionQuality,
required this.state,
});
final SignalLevel connectionQuality;
final SignalLevel positionQuality;
final DroneState state;
}
/// Verbindungsqualitaet aus Empfaenger-Linkqualitaet (LQ%) und
/// Signal-Rausch-Verhaeltnis (SNR, dB) - LQ ist der primaere Massstab (die
/// 70%-Schwelle entspricht iNAVs eigenem OSD-Alarm-Default
/// `osd_link_quality_alarm`, `fc/settings.yaml`), SNR stuft zusaetzlich von
/// gruen auf gelb herab, wenn das Rauschen trotz noch guter LQ bereits das
/// Signal ueberdeckt (SNR < 0 dB).
SignalLevel _connectionQuality({required int linkQuality, required int snrDb}) {
if (linkQuality < 50) return SignalLevel.red;
if (linkQuality < 70 || snrDb < 0) return SignalLevel.yellow;
return SignalLevel.green;
}
/// Positionsqualitaet aus Satellitenanzahl und HDOP - gaengige GNSS-
/// Faustregel (>=8 Sat. und HDOP <2.0 = gut, >=6 Sat. und HDOP <5.0 =
/// brauchbar, sonst schlecht/kein Fix).
SignalLevel _positionQuality({
required bool hasFix,
required int numSat,
required double hdop,
}) {
if (!hasFix) return SignalLevel.red;
if (numSat >= 8 && hdop < 2.0) return SignalLevel.green;
if (numSat >= 6 && hdop < 5.0) return SignalLevel.yellow;
return SignalLevel.red;
}
/// Zustand aus Armed-Status, GPS-Fix und dem rohen Navigationsmodus
/// (`MW_GPS_MODE_*`, siehe TelemetryFrame.navMode) - [connected] hat
/// Vorrang vor allem anderen (kein Telemetrie-Strom heisst, keiner der
/// anderen Werte ist aktuell), danach Emergency (15), "waypoint" nur
/// solange tatsaechlich armed und im Waypoint-Missionsmodus (3) navigiert
/// wird, "ready" markiert lediglich einen vorhandenen GPS-Fix im
/// disarmed-Zustand (kein zusaetzlicher Qualitaets-Gate durch
/// Positionsqualitaet - Nutzerentscheidung).
DroneState _droneState({
required bool connected,
required bool armed,
required bool hasFix,
required int navMode,
}) {
const navModeEmergency = 15;
const navModeWaypointMission = 3;
if (!connected) return DroneState.disconnected;
if (navMode == navModeEmergency) return DroneState.error;
if (armed && navMode == navModeWaypointMission) return DroneState.waypoint;
if (armed) return DroneState.armed;
if (hasFix) return DroneState.ready;
return DroneState.idle;
}
/// Reine Ableitung aus einem [TelemetryFrame] (siehe transport/
/// flight_controller_link.dart) - kein MSP-/Protokollwissen, nur die
/// bereits normalisierten Felder.
///
/// [connected] spiegelt, ob der Telemetrie-Strom gerade tatsaechlich Daten
/// liefert (z.B. `!telemetryProvider.hasError`, siehe fly_screen.dart) -
/// getrennt von den einzelnen Telemetriewerten, weil diese bei einem
/// Verbindungsverlust bewusst auf ihrem letzten Stand "einfrieren" (Doku:
/// "im Drone Detail Menü ist es okay, dass die Daten einfrieren"), die
/// Statuspille aber trotzdem ehrlich "disconnected" anzeigen soll statt
/// den zuletzt bekannten (ggf. laengst veralteten) Zustand fortzuschreiben.
DroneStatus computeDroneStatus({
required bool connected,
required bool armed,
required bool hasFix,
required int numSat,
required double hdop,
required int linkQuality,
required int snrDb,
required int navMode,
}) {
return DroneStatus(
connectionQuality: connected
? _connectionQuality(linkQuality: linkQuality, snrDb: snrDb)
: SignalLevel.red,
positionQuality: _positionQuality(hasFix: hasFix, numSat: numSat, hdop: hdop),
state: _droneState(connected: connected, armed: armed, hasFix: hasFix, navMode: navMode),
);
}