import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../transport/flight_controller_link.dart'; import 'telemetry_provider.dart'; /// Zuletzt vom Flightcontroller abgefragter Homepoint (Doku: "den auf der /// Drohne gelockten Homepoint abfragen") - reine Ablage, analog /// systemMessageLogProvider. Die eigentliche Abfrage-Logik (wann neu /// nachgefragt wird) sitzt getrennt in [homePointAutoRefreshProvider], aus /// demselben Grund wie dort: nur der Fly-Modus soll dafuer den Telemetrie-/ /// Transport-Stack beobachten. class HomePointNotifier extends Notifier { @override HomePoint? build() => null; void set(HomePoint? point) => state = point; } final homePointProvider = NotifierProvider(HomePointNotifier.new); /// Frischt [homePointProvider] gezielt bei drei Momenten auf, statt /// kontinuierlich (Doku: "der Homepoint muss nicht kontinuierlich abgefragt /// werden, aber an diesen drei Stellen macht es Sinn"): /// - Verbindungsaufbau/-wiederaufbau: der FC koennte seit dem letzten Mal /// einen anderen Homepoint gesetzt haben (z.B. nach einem Akkuwechsel). /// - GPS-Fix-Erwerb: vorher konnte der FC ohnehin noch keinen gueltigen /// Homepoint gesetzt haben (siehe `MspCommands.getWp`-Doku: /// `STATE(GPS_FIX_HOME)`). /// - Armen: laut iNAV-Default (`reset_home_type = FIRST_ARM`, /// `navigation.c`/`settings.yaml`) friert genau dieser Moment den bis /// dahin der Drohne folgenden Homepoint ein - vorherige Abfragen koennten /// also noch veraltet/in Bewegung gewesen sein. /// /// autoDispose wie systemMessageAutoLogProvider (dortige Doku): nur aktiv, /// waehrend irgendwer (FlyScreen) diesen Provider beobachtet, damit ein /// simpler Missionswechsel im Plan-Modus nicht ungewollt den kompletten /// Telemetrie-/Transport-Stack mit hochreisst. final homePointAutoRefreshProvider = Provider.autoDispose((ref) { TelemetryFrame? previousFrame; var hadData = false; Future refresh() async { final link = ref.read(flightControllerLinkProvider); try { ref.read(homePointProvider.notifier).set(await link.readHomePoint()); } catch (_) { // Einzelne fehlgeschlagene Abfrage ist kein Beinbruch - der naechste // Trigger (naechster Fix/Armen/Reconnect) versucht es erneut. } } ref.listen>(telemetryProvider, (previous, next) { next.whenData((frame) { final justConnected = !hadData; final fixJustAcquired = previousFrame != null && !previousFrame!.hasFix && frame.hasFix; final justArmed = previousFrame != null && !previousFrame!.armed && frame.armed; previousFrame = frame; hadData = true; if (justConnected || fixJustAcquired || justArmed) { unawaited(refresh()); } }); if (next is AsyncError) { previousFrame = null; hadData = false; } }); });