Take-off, land, RTH, the landing cancel/confirm and Stop now all go through one SafetyGate (lib/fly/safety_gate.dart). The gate sorts its preconditions into blockers and warnings: connection, flight state, battery against the thresholds, IMU warm-up, compass, critical diagnostics, GPS, home point, SD card and the RTH battery budget. It checks again right before sending. The left rail is now a state machine (lib/fly/action_rail_state.dart): Take-off becomes Land, then Cancel or Confirm landing. RTH becomes Cancel RTH. A Stop button shows while an intelligent mode is flying. Moving the aircraft needs a slide-to-confirm dialog, which can offer Precision Takeoff or set the RTH altitude. A blocked command shows why and has no slider. When the pilot is more than 30 m from home, RTH asks whether to return to them or to the original home point. The HUD gains an error stack. Its cards can be dismissed, it fits the space it has, and a new warning triggers haptic feedback. It also gets a smart-RTH countdown banner with Cancel / Go home now, a forced-landing banner, and an Aircraft Status sheet. The sheet opens from the status chip and appears before each connection's first take-off. It offers Calibrate compass/IMU and Format SD. On the bridge side this adds precisionTakeOff, setHomeLocation, compass and IMU calibration start/stop, formatStorage, and compass health in the telemetry tick. The classic flight screen stays available until the simulator run passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
2.9 KiB
Dart
68 lines
2.9 KiB
Dart
import 'state/aircraft_state.dart';
|
|
import 'state/alert_state.dart';
|
|
|
|
/// How the status chip is coloured, worst last.
|
|
enum StatusLevel { neutral, ready, caution, danger }
|
|
|
|
/// The status chip at the left of the HUD's top bar (GO 4's "Ready to Go (GPS)").
|
|
class FlightStatus {
|
|
const FlightStatus(this.text, this.level);
|
|
|
|
final String text;
|
|
final StatusLevel level;
|
|
|
|
/// GPS level the flight controller needs before it will record a home point.
|
|
static const int minGpsLevel = 3;
|
|
|
|
/// Reads the chip off the flight controller state and the live diagnostics.
|
|
/// Ordered by what the pilot most needs to know: an automatic manoeuvre in
|
|
/// progress first, then battery, then faults, then the plain flight state.
|
|
static FlightStatus of({required bool connected, required AircraftState a, AlertState? alerts}) {
|
|
if (!connected) return const FlightStatus('Disconnected', StatusLevel.neutral);
|
|
if (a.updatedAt == null) return const FlightStatus('Connecting…', StatusLevel.neutral);
|
|
|
|
final String mode = a.flightModeEnum ?? '';
|
|
final bool flying = a.isFlying == true;
|
|
final AlertSeverity? worst = alerts?.worst;
|
|
|
|
if (a.landingConfirmationNeeded == true) return const FlightStatus('Confirm landing', StatusLevel.caution);
|
|
if (a.goingHome == true || mode == 'GO_HOME') {
|
|
return const FlightStatus('Returning to Home', StatusLevel.caution);
|
|
}
|
|
if (mode == 'AUTO_LANDING' || mode == 'CONFIRM_LANDING') return const FlightStatus('Landing', StatusLevel.caution);
|
|
if (mode == 'AUTO_TAKEOFF' || mode == 'ASSISTED_TAKEOFF') return const FlightStatus('Taking off', StatusLevel.ready);
|
|
if (a.seriousLowBattery == true) return const FlightStatus('Battery critical', StatusLevel.danger);
|
|
if (a.lowBattery == true) return const FlightStatus('Low battery', StatusLevel.caution);
|
|
if (worst == AlertSeverity.critical) {
|
|
return FlightStatus(flying ? 'Warning' : 'Cannot take off', StatusLevel.danger);
|
|
}
|
|
if (a.imuPreheating == true) return const FlightStatus('IMU preheating', StatusLevel.caution);
|
|
|
|
final String fix = _positioning(a);
|
|
if (flying) {
|
|
return FlightStatus('In Flight ($fix)', worst == AlertSeverity.warning ? StatusLevel.caution : StatusLevel.ready);
|
|
}
|
|
final bool noFix = fix == 'ATTI';
|
|
return FlightStatus(
|
|
'Ready to Go ($fix)',
|
|
noFix || worst == AlertSeverity.warning ? StatusLevel.caution : StatusLevel.ready,
|
|
);
|
|
}
|
|
|
|
/// What the aircraft is holding position with: GPS, the vision system, or nothing.
|
|
static String _positioning(AircraftState a) {
|
|
if ((a.gpsSignalLevel ?? 0) >= minGpsLevel) return 'GPS';
|
|
if (a.visionPositioningBeingUsed == true) return 'Vision';
|
|
return 'ATTI';
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) => other is FlightStatus && other.text == text && other.level == level;
|
|
|
|
@override
|
|
int get hashCode => Object.hash(text, level);
|
|
|
|
@override
|
|
String toString() => 'FlightStatus($text, $level)';
|
|
}
|