Erkennung von Drone connected/disconnected repariert (MSP-Poller verschluckte Verbindungsabbrueche komplett)

Wenn die Drohne ausgeschaltet wurde, liefen die MSP-Anfragen in
MspTelemetryPoller._runCycle() zwar korrekt in den Timeout (MspClient hat
bereits eigene Zeitgrenze + Wiederholung), aber die aeussere Schleife in
_loop() hat jede Exception stillschweigend verschluckt (catch (_) {}) und
einfach den naechsten Zyklus gestartet - ohne jemals ein error: auf
_framesController zu emittieren. telemetryProvider blieb dadurch bei
einem stillen Ausbleiben der Drohne einfach auf dem letzten AsyncData(...)
Frame stehen.

systemMessageAutoLogProvider (system_message_log_provider.dart) wartet
aber genau auf einen error:-Uebergang, um "Drone disconnected" zu loggen
und sein internes hadData zurueckzusetzen - ohne diesen Uebergang blieb
nicht nur "Drone disconnected" aus, sondern beim Wiederverbinden auch
"Drone connected" (hadData war ja nie zurueckgesetzt worden). Der Nutzer
sah das Problem korrekt schon eingegrenzt: der WLAN-Connection-Log in den
Settings (wifi_connection_provider.dart) erkennt "Telemetry stream
stopped"/"Receiving telemetry" bereits richtig, weil er unabhaengig davon
direkt auf rohe eingehende UDP-Pakete schaut, nicht auf MSP-Antworten.

Fix ausschliesslich in msp_telemetry_poller.dart: nach 3 aufeinander-
folgenden fehlgeschlagenen Zyklen (vermeidet Falschmeldungen bei kurzen
Signalluecken, ein einzelner Zyklus scheitert bereits erst nach MspClients
eigenen internen Retries) wird einmalig ein addError auf den
Frames-Stream gegeben - die bereits vorhandene Logik in
systemMessageAutoLogProvider greift danach unveraendert. Keine Aenderung
an system_message_log_provider.dart noetig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Constantin Leue
2026-08-06 16:49:12 +02:00
co-authored by Claude Sonnet 5
parent a8d2731c43
commit 1b8c67a02b
2 changed files with 206 additions and 6 deletions
@@ -36,8 +36,20 @@ class MspTelemetryPoller {
static const _cycleInterval = Duration(milliseconds: 150); // ~6-7 Hz
static const _statusEveryNCycles = 3; // ~2 Hz bei 150-ms-Takt
/// Anzahl aufeinanderfolgender fehlgeschlagener Zyklen, bevor der Strom
/// einmalig einen Fehler emittiert (Doku: "Drone connected/disconnected"
/// wird nicht erkannt, wenn die Drohne ausgeschaltet wird) - jede
/// [MspClient.request]-Anfrage hat bereits ihre eigene Zeitgrenze +
/// Wiederholung (siehe dort), ein einzelner fehlgeschlagener Zyklus ist
/// also schon ein "MSP_RAW_GPS blieb trotz interner Retries 1.5s lang
/// unbeantwortet" und kein einzelner verlorener Funkframe mehr. 3 Zyklen
/// vermeiden trotzdem, dass eine kurze Signalluecke sofort als
/// "disconnected" gilt.
static const _disconnectAfterFailures = 3;
bool _running = false;
int _cycle = 0;
int _consecutiveFailures = 0;
bool _armed = false;
int? _activeWaypointIndex;
int _batteryPercent = 0;
@@ -66,12 +78,27 @@ class MspTelemetryPoller {
while (_running) {
try {
await _runCycle();
} catch (_) {
// Eine einzelne fehlgeschlagene Anfrage (Timeout/CRC/Transport
// getrennt) darf den Takt nicht stoppen - der naechste Zyklus
// startet nach der Wartezeit regulaer weiter (Doku 4: Zeitgrenze +
// Wiederholung; Wiederverbinden passiert bereits auf Transport-
// Ebene, siehe BluetoothClassicTransport).
_consecutiveFailures = 0;
} catch (error, stackTrace) {
// Ein einzelner fehlgeschlagener Zyklus darf den Takt nicht stoppen
// - der naechste Zyklus startet nach der Wartezeit regulaer weiter
// (Doku 4: Zeitgrenze + Wiederholung; Wiederverbinden passiert
// bereits auf Transport-Ebene, siehe BluetoothClassicTransport).
// ABER: ohne irgendeine Fehler-Emission auf [_framesController]
// bleibt telemetryProvider bei einem stillen Ausbleiben der Drohne
// (z.B. ausgeschaltet) einfach auf dem letzten AsyncData(...) Frame
// stehen - systemMessageAutoLogProvider (das genau auf einen
// error:-Uebergang wartet, siehe dort) bekommt dann nie mit, dass
// die Verbindung weg ist, und loggt weder "Drone disconnected" noch
// (weil hadData nie zurueckgesetzt wird) spaeter erneut "Drone
// connected". Deshalb hier einmalig ein addError, sobald genug
// Zyklen in Folge fehlgeschlagen sind - danach greift die bereits
// vorhandene Logik in systemMessageAutoLogProvider unveraendert.
_consecutiveFailures++;
if (_consecutiveFailures == _disconnectAfterFailures &&
!_framesController.isClosed) {
_framesController.addError(error, stackTrace);
}
}
await Future<void>.delayed(_cycleInterval);
}