drone status pill in footer for fly mode implemented. footer layout and sizes homogenized

This commit is contained in:
Constantin Leue
2026-08-04 15:47:53 +02:00
parent f2f2953642
commit 1a17fe5b36
12 changed files with 585 additions and 28 deletions
@@ -36,6 +36,9 @@ class TelemetryFrame {
required this.armed,
required this.batteryPercent,
required this.linkQuality,
required this.snrDb,
required this.hdop,
required this.navMode,
required this.flightMode,
this.activeWaypointIndex,
});
@@ -65,6 +68,25 @@ class TelemetryFrame {
/// Empfaenger-Linkqualitaet in Prozent (0-100).
final int linkQuality;
/// Signal-Rausch-Verhaeltnis des Uplinks in dB (siehe
/// parseMspLinkStatsSnr in msp_telemetry_codec.dart) - hoeher ist besser,
/// negative Werte bedeuten das Rauschen ueberdeckt das Signal bereits
/// teilweise trotz ggf. noch ordentlicher Linkqualitaet.
final int snrDb;
/// Horizontale Streuung der GPS-Positionsschaetzung (kleiner ist besser,
/// siehe MspGpsReading.hdop in msp_telemetry_codec.dart). Ohne Fix ein
/// sehr grosser Wert (iNAV meldet dann 99.99), nicht null.
final double hdop;
/// Roher `MW_GPS_MODE_*`-Wert aus `MSP_NAV_STATUS` (0=None, 1=Hold,
/// 2=RTH, 3=Waypoint mission, 15=Emergency) - siehe MspNavMode.mode in
/// msp_telemetry_codec.dart. Getrennt von [flightMode] (der bereits
/// formatierten Kurzbeschreibung), weil computeDroneStatus in
/// domain/telemetry/drone_status.dart den Rohwert fuer die
/// Zustandsableitung braucht.
final int navMode;
/// Menschenlesbare Kurzbeschreibung des Navigationsmodus (z.B. "Waypoint
/// mission (en route)", "Return to home (climbing)", "Idle") - siehe
/// MspNavMode.formatted in msp_telemetry_codec.dart.
@@ -96,6 +96,12 @@ class MockFlightControllerLink implements FlightControllerLink {
armed: _armed,
batteryPercent: _batteryPercent.round(),
linkQuality: 95,
snrDb: 9,
hdop: 0.9,
// MW_GPS_MODE_NAV (3), sobald armed und eine Mission aktiv ist -
// analog zu flightMode unten, damit computeDroneStatus (Doku:
// "drone state ... waypoint") auch mit Mock-Daten testbar ist.
navMode: _armed && _activeWaypointIndex != null ? 3 : 0,
flightMode: _activeWaypointIndex != null
? 'Waypoint mission (en route)'
: 'Idle',
@@ -11,6 +11,7 @@ class MspGpsReading {
required this.lon,
required this.speedMs,
required this.headingDeg,
required this.hdop,
});
/// 0 = kein Fix (`fc_msp.c`: `gpsSol.fixType`).
@@ -24,6 +25,13 @@ class MspGpsReading {
/// `groundCourse` - nur bei [hasFix] aussagekraeftig.
final double headingDeg;
/// Horizontale Streuung der Positionsschaetzung (kleiner = besser, ~1.0
/// oder darunter ist gut) - `gpsSol.hdop / HDOP_SCALE` (`gps.h`:
/// `#define HDOP_SCALE (100)`). Ohne Fix meldet iNAV hier 9999/100 =
/// 99.99 (`gps.c`: `gpsSol.hdop = 9999`), also einen sehr grossen statt
/// eines fehlenden Werts.
final double hdop;
bool get hasFix => fixType != 0;
}
@@ -37,6 +45,7 @@ MspGpsReading parseMspRawGps(Uint8List payload) {
lon: data.getInt32(6, Endian.little) / 1e7,
speedMs: data.getUint16(12, Endian.little) / 100.0,
headingDeg: data.getUint16(14, Endian.little) / 10.0,
hdop: data.getUint16(16, Endian.little) / 100.0,
);
}
@@ -133,3 +142,11 @@ int parseMspInavAnalogBatteryPercent(Uint8List payload) => payload[21];
/// Empfaenger-Linkqualitaet in Prozent (Offset 1, `rxLinkStatistics.uplinkLQ`
/// - bereits 0-100, siehe [MspCommands.inavLinkStats]).
int parseMspLinkQuality(Uint8List payload) => payload[1];
/// Parst die `MSP2_INAV_GET_LINK_STATS`-Antwort und liefert das
/// Signal-Rausch-Verhaeltnis des Uplinks in dB (Offset 2,
/// `rxLinkStatistics.uplinkSNR` - `int8_t`, `fc_msp.c` schreibt
/// `(uint8_t)rxLinkStatistics.uplinkSNR`, das Byte muss also vorzeichen-
/// behaftet zurueckgelesen werden, siehe [MspCommands.inavLinkStats]).
int parseMspLinkStatsSnr(Uint8List payload) =>
ByteData.sublistView(payload).getInt8(2);
@@ -40,6 +40,8 @@ class MspTelemetryPoller {
int? _activeWaypointIndex;
int _batteryPercent = 0;
int _linkQuality = 0;
int _snrDb = 0;
int _navMode = 0;
String _flightMode = 'Idle';
Stream<TelemetryFrame> get frames => _framesController.stream;
@@ -81,13 +83,15 @@ class MspTelemetryPoller {
);
final navStatusPayload = await _client.request(MspCommands.navStatus);
_activeWaypointIndex = parseMspNavStatusActiveWaypoint(navStatusPayload);
_flightMode = parseMspNavMode(navStatusPayload).formatted;
final navMode = parseMspNavMode(navStatusPayload);
_navMode = navMode.mode;
_flightMode = navMode.formatted;
_batteryPercent = parseMspInavAnalogBatteryPercent(
await _client.request(MspCommands.inavAnalog),
);
_linkQuality = parseMspLinkQuality(
await _client.request(MspCommands.inavLinkStats),
);
final linkStatsPayload = await _client.request(MspCommands.inavLinkStats);
_linkQuality = parseMspLinkQuality(linkStatsPayload);
_snrDb = parseMspLinkStatsSnr(linkStatsPayload);
}
if (!_framesController.isClosed) {
@@ -102,6 +106,9 @@ class MspTelemetryPoller {
armed: _armed,
batteryPercent: _batteryPercent,
linkQuality: _linkQuality,
snrDb: _snrDb,
hdop: gps.hdop,
navMode: _navMode,
flightMode: _flightMode,
activeWaypointIndex: _activeWaypointIndex,
));