/// 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)"). enum DroneState { idle, ready, armed, waypoint, 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) - Emergency (15) hat /// Vorrang vor allem anderen, "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 armed, required bool hasFix, required int navMode, }) { const navModeEmergency = 15; const navModeWaypointMission = 3; 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. DroneStatus computeDroneStatus({ required bool armed, required bool hasFix, required int numSat, required double hdop, required int linkQuality, required int snrDb, required int navMode, }) { return DroneStatus( connectionQuality: _connectionQuality(linkQuality: linkQuality, snrDb: snrDb), positionQuality: _positionQuality(hasFix: hasFix, numSat: numSat, hdop: hdop), state: _droneState(armed: armed, hasFix: hasFix, navMode: navMode), ); }