live mission details in footer implemented
This commit is contained in:
@@ -69,6 +69,12 @@ class TelemetryFrame {
|
||||
/// mission (en route)", "Return to home (climbing)", "Idle") - siehe
|
||||
/// MspNavMode.formatted in msp_telemetry_codec.dart.
|
||||
final String flightMode;
|
||||
|
||||
/// 0-basierter Index des gerade angeflogenen Wegpunkts in der
|
||||
/// App-eigenen Wegpunktliste (z.B. `currentMissionProvider`), oder null,
|
||||
/// wenn keine Mission aktiv ist. Bei MSP bereits aus dem 1-basierten
|
||||
/// `activeWpNumber` umgerechnet (siehe parseMspNavStatusActiveWaypoint in
|
||||
/// msp_telemetry_codec.dart).
|
||||
final int? activeWaypointIndex;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,31 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import '../../domain/waypoint/flat_waypoint_list.dart';
|
||||
import '../flight_controller_link.dart';
|
||||
|
||||
/// Synthetische Telemetrie fuer UI-Entwicklung/Tests ohne Hardware oder SITL
|
||||
/// (Architektur-Doku 3.1).
|
||||
///
|
||||
/// Verankert am ersten Wegpunkt der uebergebenen Mission (Doku: "solange die
|
||||
/// Drohne nicht verbunden ist, Mock-Daten fuer die neue Live-Details-
|
||||
/// Ansicht nutzbar machen") statt an einem fest verdrahteten Ort (frueher
|
||||
/// Berlin) - dadurch liegt die simulierte Position tatsaechlich auf der
|
||||
/// gerade bearbeiteten Route, und activeWaypointIndex ist von Anfang an
|
||||
/// gesetzt (0, "erster Wegpunkt aktiv"), auch ohne den noch nicht
|
||||
/// umgesetzten Missions-Upload-Flow. Fehlt eine Mission (keine Wegpunkte),
|
||||
/// bleibt der alte Berlin-Fallback bestehen, damit die Klasse auch ganz
|
||||
/// ohne Mission nutzbar ist.
|
||||
class MockFlightControllerLink implements FlightControllerLink {
|
||||
MockFlightControllerLink({List<Waypoint> initialWaypoints = const []})
|
||||
: _anchorLat = initialWaypoints.isEmpty ? 52.5 : initialWaypoints.first.lat,
|
||||
_anchorLon = initialWaypoints.isEmpty ? 13.4 : initialWaypoints.first.lon,
|
||||
_activeWaypointIndex = initialWaypoints.isEmpty ? null : 0;
|
||||
|
||||
final double _anchorLat;
|
||||
final double _anchorLon;
|
||||
final _random = math.Random();
|
||||
|
||||
bool _armed = false;
|
||||
int? _activeWaypointIndex;
|
||||
StreamController<TelemetryFrame>? _telemetryController;
|
||||
@@ -13,6 +33,16 @@ class MockFlightControllerLink implements FlightControllerLink {
|
||||
double _heading = 0;
|
||||
double _batteryPercent = 100;
|
||||
|
||||
/// Aktuelle Drift vom Ankerpunkt in Metern (Nord/Ost) - Zufalls-Trudeln
|
||||
/// innerhalb eines 10-m-Radius statt eines fest stehenden Punkts, damit
|
||||
/// auch die Distanz/ETA-Anzeige der neuen Details-Pille sichtbar auf
|
||||
/// Werteaenderungen reagiert (Doku 9: UI-Entwicklung ohne Hardware).
|
||||
double _driftNorthM = 0;
|
||||
double _driftEastM = 0;
|
||||
static const _driftRadiusM = 10.0;
|
||||
static const _driftStepM = 1.5;
|
||||
static const _metersPerDegreeLat = 111320.0;
|
||||
|
||||
@override
|
||||
FcCapabilities get capabilities => const FcCapabilities(
|
||||
supportsMultiMission: true,
|
||||
@@ -37,9 +67,27 @@ class MockFlightControllerLink implements FlightControllerLink {
|
||||
// Langsam sinkender Akkustand, damit die Anzeige auch ohne Hardware
|
||||
// sichtbar auf Werteaenderungen reagiert (Doku 9).
|
||||
_batteryPercent = (_batteryPercent - 0.1).clamp(0, 100);
|
||||
|
||||
// Zufallsschritt, danach auf den 10-m-Radius um den Ankerpunkt
|
||||
// zurueckgeklemmt statt frei wegzulaufen.
|
||||
_driftNorthM += (_random.nextDouble() - 0.5) * 2 * _driftStepM;
|
||||
_driftEastM += (_random.nextDouble() - 0.5) * 2 * _driftStepM;
|
||||
final driftMagnitude = math.sqrt(
|
||||
_driftNorthM * _driftNorthM + _driftEastM * _driftEastM,
|
||||
);
|
||||
if (driftMagnitude > _driftRadiusM) {
|
||||
final scale = _driftRadiusM / driftMagnitude;
|
||||
_driftNorthM *= scale;
|
||||
_driftEastM *= scale;
|
||||
}
|
||||
final metersPerDegreeLon =
|
||||
_metersPerDegreeLat * math.cos(_anchorLat * math.pi / 180);
|
||||
final lat = _anchorLat + _driftNorthM / _metersPerDegreeLat;
|
||||
final lon = _anchorLon + _driftEastM / metersPerDegreeLon;
|
||||
|
||||
_telemetryController?.add(TelemetryFrame(
|
||||
lat: 52.5,
|
||||
lon: 13.4,
|
||||
lat: lat,
|
||||
lon: lon,
|
||||
hasFix: true,
|
||||
numSat: 12,
|
||||
altitudeM: 120,
|
||||
|
||||
@@ -57,12 +57,23 @@ bool parseMspInavStatusArmed(Uint8List payload) {
|
||||
return (armingFlags & MspArmingFlags.armed) != 0;
|
||||
}
|
||||
|
||||
/// Parst die `MSP_NAV_STATUS`-Antwort und liefert den aktiven
|
||||
/// Wegpunktindex, oder null, wenn keine Mission aktiv ist (`activeWpNumber
|
||||
/// == 0`, siehe [MspCommands.navStatus]).
|
||||
/// Parst die `MSP_NAV_STATUS`-Antwort und liefert den aktiven Wegpunkt als
|
||||
/// 0-basierten Index in die App-eigene Wegpunktliste, oder null, wenn keine
|
||||
/// Mission aktiv ist (`activeWpNumber == 0`, siehe [MspCommands.navStatus]).
|
||||
///
|
||||
/// `activeWpNumber` selbst ist 1-basiert (`navigation.c`: `NAV_Status.
|
||||
/// activeWpIndex = posControl.activeWaypointIndex - posControl.startWpIndex;
|
||||
/// NAV_Status.activeWpNumber = NAV_Status.activeWpIndex + 1;`) - bei einem
|
||||
/// einzelnen, komplett hochgeladenen Missions-Upload (kein Multi-Mission-
|
||||
/// Jump, `startWpIndex` = 0) entspricht `activeWpNumber - 1` also exakt dem
|
||||
/// 0-basierten Index in [Waypoint]-Listen wie `currentMissionProvider`.
|
||||
/// Frueher wurde hier der Rohwert unveraendert durchgereicht, was beim
|
||||
/// Indizieren in die Wegpunktliste zu einem Off-by-One fuehrte (durch
|
||||
/// Zufall unauffaellig, weil [MockFlightControllerLink] von Anfang an
|
||||
/// 0-basiert gezaehlt hat).
|
||||
int? parseMspNavStatusActiveWaypoint(Uint8List payload) {
|
||||
final activeWpNumber = payload[3];
|
||||
return activeWpNumber == 0 ? null : activeWpNumber;
|
||||
return activeWpNumber == 0 ? null : activeWpNumber - 1;
|
||||
}
|
||||
|
||||
/// Parst `mode`/`state` aus der `MSP_NAV_STATUS`-Antwort (Byte 0/1, siehe
|
||||
|
||||
Reference in New Issue
Block a user