From 9cece7dbb6bd36617b269241b89e2b4e34240660 Mon Sep 17 00:00:00 2001 From: Constantin Leue <77660791+Consti3D@users.noreply.github.com> Date: Thu, 6 Aug 2026 15:32:56 +0200 Subject: [PATCH] Drone Status Menue: Sensor-Status, Arming, Temperaturen und Steig-/Sinkrate hinzugefuegt Neue Zeile ganz oben mit farblich kodierten Sensor-Badges (ACC/BARO/MAG/ GPS/RNG/OF/PITOT/TEMP, aus dem sensorStatus-Bitfeld von MSP2_INAV_STATUS, zuvor schon dokumentiert aber ungenutzt), darunter ein Zeilenpaar fuer Arming-Status und die ersten 3 Temperatursensoren (neu: MSP2_INAV_ TEMPERATURES, 0x201E). Ans Ende der Liste die Steig-/Sinkrate (vario aus MSP_ALTITUDE, bislang nur die Hoehe selbst wurde daraus gelesen). - msp_commands.dart: inavTemperatures-Konstante ergaenzt; die Sensor- Status-Bits (bisher nur als Doc-Kommentar bei MSP2_INAV_STATUS notiert) zu echten Konstanten (MspSensorStatusBits) promoviert, da jetzt tatsaechlich gebraucht. - msp_telemetry_codec.dart: parseMspAltitudeVerticalSpeedMs, parseMspInavStatusSensorStatus, parseMspInavTemperaturesC ergaenzt + Unit-Tests. - TelemetryFrame: sensorStatusBits (Bitmaske, protokollneutral durchgereicht wie navMode), temperaturesC (erste 3 Sensoren, null je nicht konfiguriertem Slot), verticalSpeedMs. - msp_telemetry_poller.dart: vario kommt aus derselben MSP_ALTITUDE- Antwort wie die Hoehe (keine zusaetzliche Anfrage), sensorStatus aus derselben MSP2_INAV_STATUS-Antwort wie ARMED; MSP2_INAV_TEMPERATURES neu im 2-Hz-Statuszyklus abgefragt. - MockFlightControllerLink: synthetische Sensor-/Temperatur-/Vario-Werte (kein Pitot/Rangefinder/Opflow am T1 Ranger vorgesehen), leicht schwankend, damit die neuen Felder auch ohne Hardware sichtbar auf Werteaenderungen reagieren. - drone_status_messages_panel.dart: eigene Sensor-Status-Zeile (lokale Bit-Konstanten statt MSP-Import, analog zum bestehenden navMode-Muster in domain/telemetry/drone_status.dart, damit die UI protokollneutral bleibt), Arming+Temperaturen-Zeilenpaar, Vertical-speed-Zeile am Ende. Auf dem Pixel_10a-Emulator verifiziert: Sensor-Badges gruen/grau je nach Bitmaske, Arming/Temperaturen-Paar, Vertical speed am Listenende. Co-Authored-By: Claude Sonnet 5 --- app/lib/transport/flight_controller_link.dart | 19 +++ .../mock/mock_flight_controller_link.dart | 25 ++++ app/lib/transport/msp/msp_commands.dart | 41 +++++- .../transport/msp/msp_telemetry_codec.dart | 30 +++++ .../transport/msp/msp_telemetry_poller.dart | 29 +++-- .../widgets/drone_status_messages_panel.dart | 122 ++++++++++++++++-- app/test/domain/system_message_test.dart | 3 + .../msp/msp_telemetry_codec_test.dart | 73 +++++++++++ .../system_message_log_provider_test.dart | 3 + 9 files changed, 324 insertions(+), 21 deletions(-) diff --git a/app/lib/transport/flight_controller_link.dart b/app/lib/transport/flight_controller_link.dart index e0f9c03..e122690 100644 --- a/app/lib/transport/flight_controller_link.dart +++ b/app/lib/transport/flight_controller_link.dart @@ -42,6 +42,9 @@ class TelemetryFrame { required this.hdop, required this.navMode, required this.flightMode, + required this.sensorStatusBits, + required this.temperaturesC, + required this.verticalSpeedMs, this.activeWaypointIndex, }); @@ -102,6 +105,22 @@ class TelemetryFrame { /// MspNavMode.formatted in msp_telemetry_codec.dart. final String flightMode; + /// Rohes `sensorStatus`-Bitfeld aus `MSP2_INAV_STATUS` (protokollneutral + /// als Bitmaske durchgereicht, analog zu [navMode]) - Bit-Bedeutung siehe + /// `MspSensorStatusBits` in `msp_commands.dart`. `0` bei + /// [MockFlightControllerLink]/fehlendem Frame bedeutet "kein Sensor + /// gemeldet", nicht zwingend "kein Sensor vorhanden". + final int sensorStatusBits; + + /// Die ersten 3 Temperatursensoren in °C (siehe + /// `MspCommands.inavTemperatures`), `null` je Slot ohne konfigurierten/ + /// gueltigen Sensor. Immer genau 3 Eintraege lang. + final List temperaturesC; + + /// Steig-/Sinkrate in m/s, positiv = Steigen (siehe + /// `parseMspAltitudeVerticalSpeedMs` in msp_telemetry_codec.dart). + final double verticalSpeedMs; + /// 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 diff --git a/app/lib/transport/mock/mock_flight_controller_link.dart b/app/lib/transport/mock/mock_flight_controller_link.dart index 2c524e6..2d1cf6e 100644 --- a/app/lib/transport/mock/mock_flight_controller_link.dart +++ b/app/lib/transport/mock/mock_flight_controller_link.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import '../../domain/waypoint/flat_waypoint_list.dart'; import '../flight_controller_link.dart'; +import '../msp/msp_commands.dart'; /// Synthetische Telemetrie fuer UI-Entwicklung/Tests ohne Hardware oder SITL /// (Architektur-Doku 3.1). @@ -42,6 +43,7 @@ class MockFlightControllerLink implements FlightControllerLink { Timer? _ticker; double _heading = 0; double _batteryPercent = 100; + int _tickCount = 0; /// Aktuelle Drift vom Ankerpunkt in Metern (Nord/Ost) - Zufalls-Trudeln /// innerhalb eines 10-m-Radius statt eines fest stehenden Punkts, damit @@ -77,6 +79,7 @@ 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); + _tickCount++; // Zufallsschritt, danach auf den 10-m-Radius um den Ankerpunkt // zurueckgeklemmt statt frei wegzulaufen. @@ -125,6 +128,28 @@ class MockFlightControllerLink implements FlightControllerLink { flightMode: _activeWaypointIndex != null ? 'Waypoint mission (en route)' : 'Idle', + // Kein Pitot/Rangefinder/Optical-Flow am T1 Ranger vorgesehen (Doku + // Architektur 6: "MSPV2_INAV_AIR_SPEED ... fuer den T1 Ranger + // aktuell nicht relevant") - die uebrigen Sensoren gelten als + // vorhanden/gesund, damit die Sensor-Status-Zeile im Drone-Status- + // Menue sowohl gruene als auch graue Badges zeigt. + sensorStatusBits: MspSensorStatusBits.acc | + MspSensorStatusBits.baro | + MspSensorStatusBits.mag | + MspSensorStatusBits.gps | + MspSensorStatusBits.temp, + // Leichtes Schwanken um drei Basiswerte statt fester Zahlen, damit + // die Temperaturfelder ebenfalls sichtbar auf Werteaenderungen + // reagieren (Doku 9). + temperaturesC: [ + 28.0 + math.sin(_tickCount * 0.05) * 1.5, + 34.0 + math.sin(_tickCount * 0.07) * 2.0, + 46.0 + math.sin(_tickCount * 0.06) * 3.0, + ], + // Sinuskurve statt fester 0 - die Mock-Hoehe selbst bleibt + // konstant (siehe altitudeM oben), die Steig-/Sinkrate soll aber + // trotzdem sichtbar zwischen Steigen/Sinken wechseln koennen. + verticalSpeedMs: math.sin(_tickCount * 0.3) * 2.5, activeWaypointIndex: _activeWaypointIndex, )); }); diff --git a/app/lib/transport/msp/msp_commands.dart b/app/lib/transport/msp/msp_commands.dart index 1185de2..af2c781 100644 --- a/app/lib/transport/msp/msp_commands.dart +++ b/app/lib/transport/msp/msp_commands.dart @@ -31,6 +31,10 @@ abstract final class MspCommands { static const int setWp = 209; /// Response: i32 estAlt(cm), i16 vario(cm/s), i32 baroAlt(cm). + /// `vario` ist `getEstimatedActualVelocity(Z)` - dieselbe Achse/dasselbe + /// Vorzeichen wie `estAlt` (`getEstimatedActualPosition(Z)`, beide aus + /// `navGetCurrentActualPositionAndVelocity()`, `navigation.c`), also + /// positiv = Steigen, negativ = Sinken. /// (`fc_msp.c`, `case MSP_ALTITUDE`) static const int altitude = 109; @@ -44,10 +48,8 @@ abstract final class MspCommands { /// (`fc_msp.c`, `case MSP2_INAV_STATUS`; ID aus /// `msp_protocol_v2_inav.h`: `#define MSP2_INAV_STATUS 0x2000`) /// - /// Bit-Layout `sensorStatus` (`packSensorStatus()` in `fc_msp_box.c`): - /// Bit 0 ACC, 1 BARO, 2 MAG, 3 GPS, 4 RANGEFINDER, 5 OPFLOW, 6 PITOT, - /// 7 TEMP (je 1 = Sensor vorhanden/aktiviert); Bits 8-14 unbenutzt; - /// Bit 15 = Hardware-Defekt (`!isHardwareHealthy()`). + /// Bit-Layout `sensorStatus` (`packSensorStatus()` in `fc_msp_box.c`) - + /// siehe [MspSensorStatusBits]. /// /// Bit-Layout `armingFlags` (`armingFlag_e` in `fc/runtime_config.h`) - /// siehe [MspArmingFlags]. @@ -88,6 +90,16 @@ abstract final class MspCommands { /// i8 uplinkSnr. (`fc_msp.c`, `case MSP2_INAV_GET_LINK_STATS`; ID aus /// `msp_protocol_v2_inav.h`: `#define MSP2_INAV_GET_LINK_STATS 0x2103`) static const int inavLinkStats = 0x2103; + + /// Response (`MAX_TEMP_SENSORS` = 8 Slots, je i16, 0.1°C-Schritte, + /// `sensors/temperature.h`: "Temperature is returned in degC*10"): + /// ungueltiger/nicht konfigurierter Sensor liefert `-1000` + /// (`fc_msp.c`, `case MSP2_INAV_TEMPERATURES`: `sbufWriteU16(dst, valid + /// ? temperature : -1000)`, braucht `USE_TEMPERATURE_SENSOR` + + /// konfigurierte Sensoren, sonst dauerhaft `-1000` fuer alle 8 Slots). + /// ID aus `msp_protocol_v2_inav.h`: + /// `#define MSP2_INAV_TEMPERATURES 0x201E`. + static const int inavTemperatures = 0x201E; } /// Bits von `armingFlags` (`armingFlag_e` in `fc/runtime_config.h`, iNAV @@ -110,3 +122,24 @@ abstract final class MspCommands { abstract final class MspArmingFlags { static const int armed = 1 << 2; } + +/// Bits von `sensorStatus` (`packSensorStatus()` in `fc_msp_box.c`, Teil +/// der `MSP2_INAV_STATUS`-Antwort, siehe [MspCommands.inavStatus]) - Bits +/// 0-7 melden je, ob der Sensor als vorhanden/aktiviert erkannt wurde +/// (`sensors(SENSOR_*)`), unabhaengig von einer eigenen Kalibrierung/einem +/// gueltigen Messwert. Bits 8-14 unbenutzt. +abstract final class MspSensorStatusBits { + static const int acc = 1 << 0; + static const int baro = 1 << 1; + static const int mag = 1 << 2; + static const int gps = 1 << 3; + static const int rangefinder = 1 << 4; + static const int opflow = 1 << 5; + static const int pitot = 1 << 6; + static const int temp = 1 << 7; + + /// `!isHardwareHealthy()` - mind. ein Sensor meldet einen Hardware-Defekt + /// (I2C-Fehler etc.), unabhaengig davon, welcher der Bits 0-7 betroffen + /// ist. + static const int hardwareFailure = 1 << 15; +} diff --git a/app/lib/transport/msp/msp_telemetry_codec.dart b/app/lib/transport/msp/msp_telemetry_codec.dart index d5f76b2..602368d 100644 --- a/app/lib/transport/msp/msp_telemetry_codec.dart +++ b/app/lib/transport/msp/msp_telemetry_codec.dart @@ -56,6 +56,14 @@ double parseMspAltitudeMeters(Uint8List payload) { return data.getInt32(0, Endian.little) / 100.0; } +/// Parst die `MSP_ALTITUDE`-Antwort und liefert die vertikale Geschwindigkeit +/// (Steig-/Sinkrate) in m/s, positiv = Steigen (Offset 4, i16, siehe +/// [MspCommands.altitude]). +double parseMspAltitudeVerticalSpeedMs(Uint8List payload) { + final data = ByteData.sublistView(payload); + return data.getInt16(4, Endian.little) / 100.0; +} + /// Parst die `MSP2_INAV_STATUS`-Antwort und liefert, ob der ARMED-Bit in /// `armingFlags` gesetzt ist (siehe [MspCommands.inavStatus]). bool parseMspInavStatusArmed(Uint8List payload) { @@ -66,6 +74,14 @@ bool parseMspInavStatusArmed(Uint8List payload) { return (armingFlags & MspArmingFlags.armed) != 0; } +/// Parst die `MSP2_INAV_STATUS`-Antwort und liefert das rohe `sensorStatus`- +/// Bitfeld (Offset 4, siehe [MspSensorStatusBits] fuer die Bit-Bedeutung +/// und [MspCommands.inavStatus]). +int parseMspInavStatusSensorStatus(Uint8List payload) { + final data = ByteData.sublistView(payload); + return data.getUint16(4, Endian.little); +} + /// 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]). @@ -164,3 +180,17 @@ int parseMspLinkQuality(Uint8List payload) => payload[1]; /// behaftet zurueckgelesen werden, siehe [MspCommands.inavLinkStats]). int parseMspLinkStatsSnr(Uint8List payload) => ByteData.sublistView(payload).getInt8(2); + +/// Parst die `MSP2_INAV_TEMPERATURES`-Antwort und liefert die Werte der +/// ersten 3 Temperatursensoren in °C, `null` je Slot ohne konfigurierten/ +/// gueltigen Sensor (Rohwert `-1000`, siehe [MspCommands.inavTemperatures]). +/// Absichtlich nur die ersten 3 von bis zu 8 moeglichen Slots (Doku Drone +/// Status Menue: "die ersten 3 temperaturen") - fuer mehr besteht kein +/// UI-Bedarf. +List parseMspInavTemperaturesC(Uint8List payload) { + final data = ByteData.sublistView(payload); + return List.generate(3, (i) { + final raw = data.getInt16(i * 2, Endian.little); + return raw <= -1000 ? null : raw / 10.0; + }); +} diff --git a/app/lib/transport/msp/msp_telemetry_poller.dart b/app/lib/transport/msp/msp_telemetry_poller.dart index f8f31d7..2237950 100644 --- a/app/lib/transport/msp/msp_telemetry_poller.dart +++ b/app/lib/transport/msp/msp_telemetry_poller.dart @@ -14,11 +14,13 @@ import 'msp_telemetry_codec.dart'; /// /// - Position/Lage/Hoehe (5-10 Hz): jeden Zyklus (`MSP_RAW_GPS` + /// `MSP_ALTITUDE`). -/// - Status/Flugmodus/Akku/Link (2 Hz): jeden [_statusEveryNCycles]-ten -/// Zyklus (`MSP2_INAV_STATUS`, `MSP_NAV_STATUS`, `MSP2_INAV_ANALOG`, -/// `MSP2_INAV_GET_LINK_STATS`) - Flugmodus wird aus derselben +/// - Status/Flugmodus/Akku/Link/Temperaturen (2 Hz): jeden +/// [_statusEveryNCycles]-ten Zyklus (`MSP2_INAV_STATUS`, `MSP_NAV_STATUS`, +/// `MSP2_INAV_ANALOG`, `MSP2_INAV_GET_LINK_STATS`, +/// `MSP2_INAV_TEMPERATURES`) - Flugmodus wird aus derselben /// `MSP_NAV_STATUS`-Antwort gelesen wie der aktive Wegpunkt, keine -/// zusaetzliche Anfrage noetig. +/// zusaetzliche Anfrage noetig. `sensorStatus` ebenso aus derselben +/// `MSP2_INAV_STATUS`-Antwort wie der ARMED-Status. /// /// Der Strom wird NICHT auf einen gueltigen GPS-Fix gegated - jeder Zyklus /// emittiert ein [TelemetryFrame], auch ohne Fix (dann mit `hasFix: false` @@ -45,6 +47,8 @@ class MspTelemetryPoller { int _snrDb = 0; int _navMode = 0; String _flightMode = 'Idle'; + int _sensorStatusBits = 0; + List _temperaturesC = const [null, null, null]; Stream get frames => _framesController.stream; @@ -75,14 +79,15 @@ class MspTelemetryPoller { Future _runCycle() async { final gps = parseMspRawGps(await _client.request(MspCommands.rawGps)); - final altitudeM = - parseMspAltitudeMeters(await _client.request(MspCommands.altitude)); + final altitudePayload = await _client.request(MspCommands.altitude); + final altitudeM = parseMspAltitudeMeters(altitudePayload); + final verticalSpeedMs = parseMspAltitudeVerticalSpeedMs(altitudePayload); _cycle++; if (_cycle % _statusEveryNCycles == 0) { - _armed = parseMspInavStatusArmed( - await _client.request(MspCommands.inavStatus), - ); + final statusPayload = await _client.request(MspCommands.inavStatus); + _armed = parseMspInavStatusArmed(statusPayload); + _sensorStatusBits = parseMspInavStatusSensorStatus(statusPayload); final navStatusPayload = await _client.request(MspCommands.navStatus); _activeWaypointIndex = parseMspNavStatusActiveWaypoint(navStatusPayload); final navMode = parseMspNavMode(navStatusPayload); @@ -95,6 +100,9 @@ class MspTelemetryPoller { final linkStatsPayload = await _client.request(MspCommands.inavLinkStats); _linkQuality = parseMspLinkQuality(linkStatsPayload); _snrDb = parseMspLinkStatsSnr(linkStatsPayload); + final temperaturesPayload = + await _client.request(MspCommands.inavTemperatures); + _temperaturesC = parseMspInavTemperaturesC(temperaturesPayload); } if (!_framesController.isClosed) { @@ -115,6 +123,9 @@ class MspTelemetryPoller { hdop: gps.hdop, navMode: _navMode, flightMode: _flightMode, + sensorStatusBits: _sensorStatusBits, + temperaturesC: _temperaturesC, + verticalSpeedMs: verticalSpeedMs, activeWaypointIndex: _activeWaypointIndex, )); } diff --git a/app/lib/ui/widgets/drone_status_messages_panel.dart b/app/lib/ui/widgets/drone_status_messages_panel.dart index 0c84f40..006ffe4 100644 --- a/app/lib/ui/widgets/drone_status_messages_panel.dart +++ b/app/lib/ui/widgets/drone_status_messages_panel.dart @@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../domain/telemetry/drone_status.dart'; import '../../domain/telemetry/system_message.dart'; import '../../domain/telemetry/telemetry_field_status.dart'; +import '../../transport/flight_controller_link.dart'; import '../dmc_colors.dart'; import '../providers/active_drone_profile_provider.dart'; import '../providers/system_message_log_provider.dart'; @@ -136,13 +137,30 @@ class _DroneStatusMessagesPanelState extends ConsumerState t == null ? '—' : '${t.round()}°').join(' / '); + } + + String _formatVerticalSpeed(TelemetryFrame? frame) { + if (frame == null) return '—'; + final v = frame.verticalSpeedMs; + final sign = v >= 0 ? '+' : '-'; + return '$sign${v.abs().toStringAsFixed(1)} m/s'; + } + // --- System Messages --- Widget _messagesTab() { diff --git a/app/test/domain/system_message_test.dart b/app/test/domain/system_message_test.dart index 383fa3b..49773a6 100644 --- a/app/test/domain/system_message_test.dart +++ b/app/test/domain/system_message_test.dart @@ -26,6 +26,9 @@ TelemetryFrame _frame({ hdop: 1.0, navMode: navMode, flightMode: 'Idle', + sensorStatusBits: 0, + temperaturesC: const [null, null, null], + verticalSpeedMs: 0, ); } diff --git a/app/test/transport/msp/msp_telemetry_codec_test.dart b/app/test/transport/msp/msp_telemetry_codec_test.dart index c7421af..d83fa0b 100644 --- a/app/test/transport/msp/msp_telemetry_codec_test.dart +++ b/app/test/transport/msp/msp_telemetry_codec_test.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; +import 'package:dmc_app/transport/msp/msp_commands.dart'; import 'package:dmc_app/transport/msp/msp_telemetry_codec.dart'; void main() { @@ -62,6 +63,78 @@ void main() { }); }); + group('parseMspAltitudeVerticalSpeedMs', () { + test('vario in cm/s wird zu m/s, positiv = Steigen', () { + final data = ByteData(10); + data.setInt16(4, 250, Endian.little); // 2.5 m/s Steigen + expect( + parseMspAltitudeVerticalSpeedMs(data.buffer.asUint8List()), + closeTo(2.5, 1e-9), + ); + }); + + test('negativer vario-Wert bedeutet Sinken', () { + final data = ByteData(10); + data.setInt16(4, -180, Endian.little); // -1.8 m/s Sinken + expect( + parseMspAltitudeVerticalSpeedMs(data.buffer.asUint8List()), + closeTo(-1.8, 1e-9), + ); + }); + }); + + group('parseMspInavStatusSensorStatus', () { + Uint8List statusPayload(int sensorStatus) { + final data = ByteData(22); + data.setUint16(4, sensorStatus, Endian.little); + return data.buffer.asUint8List(); + } + + test('liest das rohe sensorStatus-Bitfeld an Offset 4', () { + expect( + parseMspInavStatusSensorStatus( + statusPayload(MspSensorStatusBits.acc | MspSensorStatusBits.gps), + ), + MspSensorStatusBits.acc | MspSensorStatusBits.gps, + ); + }); + + test('Hardware-Defekt-Bit (1<<15) wird mit uebertragen', () { + final bits = parseMspInavStatusSensorStatus( + statusPayload(MspSensorStatusBits.hardwareFailure), + ); + expect(bits & MspSensorStatusBits.hardwareFailure, isNot(0)); + }); + + test('keine Sensoren gemeldet', () { + expect(parseMspInavStatusSensorStatus(statusPayload(0)), 0); + }); + }); + + group('parseMspInavTemperaturesC', () { + test('liest die ersten 3 von bis zu 8 Slots in 0.1°C-Schritten', () { + final data = ByteData(16); // 8 x i16 + data.setInt16(0, 285, Endian.little); // 28.5°C + data.setInt16(2, 320, Endian.little); // 32.0°C + data.setInt16(4, -1000, Endian.little); // ungueltig + data.setInt16(6, 999, Endian.little); // 4. Slot wird ignoriert + + final temps = parseMspInavTemperaturesC(data.buffer.asUint8List()); + + expect(temps, hasLength(3)); + expect(temps[0], closeTo(28.5, 1e-9)); + expect(temps[1], closeTo(32.0, 1e-9)); + expect(temps[2], isNull); + }); + + test('Werte unterhalb des Sentinels gelten ebenfalls als ungueltig', () { + final data = ByteData(16); + data.setInt16(0, -1250, Endian.little); + final temps = parseMspInavTemperaturesC(data.buffer.asUint8List()); + expect(temps[0], isNull); + }); + }); + group('parseMspInavStatusArmed', () { Uint8List statusPayload(int armingFlags) { final data = ByteData(22); diff --git a/app/test/ui/providers/system_message_log_provider_test.dart b/app/test/ui/providers/system_message_log_provider_test.dart index 33853c0..467d76c 100644 --- a/app/test/ui/providers/system_message_log_provider_test.dart +++ b/app/test/ui/providers/system_message_log_provider_test.dart @@ -27,6 +27,9 @@ TelemetryFrame _frame({bool hasFix = true, int numSat = 10}) => TelemetryFrame( hdop: 1.0, navMode: 0, flightMode: 'Idle', + sensorStatusBits: 0, + temperaturesC: const [null, null, null], + verticalSpeedMs: 0, ); typedef _ConnectionSettings = ({