diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1d5e8f2bd1d..3cbc59b3cd6 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -94,6 +94,7 @@ 1. [A32NX/FWC] Add FCU faults - @tracernz (Mike) 1. [ELEC] Improved elec system startup behaviour - @Gurgel100 (Pascal) - @saschl 1. [A380X] Improve pilot and copilot camera positions - @heclak (Heclak) +1. [A380X/MFD] Fix PERF APPR minimums input logic - @Pruznak (Pruznak) ## 0.12.0 diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts index e2d1092e4d3..cf1bf0cfd0b 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts @@ -473,7 +473,8 @@ export class FmcAircraftInterface { const inRange = this.shouldTransmitMinimums(distanceToDestination); const mda = this.fmgc.data.approachBaroMinimum.get(); - const dh = this.fmgc.data.approachRadioMinimum.get(); + const dh = + typeof this.fmgc.data.approachRadioMinimum.get() === 'string' ? null : this.fmgc.data.approachRadioMinimum.get(); const mdaValid = inRange && mda !== null; const dhValid = !mdaValid && inRange && typeof dh === 'number'; diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts index 9b7b741d070..8b3d9a5cf23 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts @@ -291,7 +291,7 @@ export class FmgcData { public readonly approachBaroMinimum = Subject.create(null); /** in feet. null if not set. */ - public readonly approachRadioMinimum = Subject.create(null); + public readonly approachRadioMinimum = Subject.create(null); public readonly approachVref = Subject.create(129); diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx index 7baa4383e7d..e4fb7971046 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx @@ -13,6 +13,7 @@ import './MfdFmsPerf.scss'; import { AltitudeFormat, AltitudeOrFlightLevelFormat, + RadioMinimumFormat, CostIndexFormat, DescentRateFormat, FlightLevelFormat, @@ -2505,12 +2506,23 @@ export class MfdFmsPerf extends FmsPage {
BARO - dataEntryFormat={new AltitudeFormat(Subject.create(0), Subject.create(maxCertifiedAlt))} + dataEntryFormat={new AltitudeFormat(Subject.create(1), Subject.create(maxCertifiedAlt))} dataHandlerDuringValidation={async (v) => { - SimVar.SetSimVarValue('L:AIRLINER_MINIMUM_DESCENT_ALTITUDE', 'feet', v); + if (!this.props.fmcService.master?.fmgc.data.approachRadioMinimum.get()) { + if (v === null) { + SimVar.SetSimVarValue('L:AIRLINER_MINIMUM_DESCENT_ALTITUDE', 'feet', 0); + } else { + SimVar.SetSimVarValue('L:AIRLINER_MINIMUM_DESCENT_ALTITUDE', 'feet', v); + } + } }} mandatory={Subject.create(false)} - value={this.props.fmcService.master.fmgc.data.approachBaroMinimum} + value={this.props.fmcService.master?.fmgc.data.approachBaroMinimum} + onModified={(v) => { + if (!this.props.fmcService.master?.fmgc.data.approachRadioMinimum.get()) { + this.props.fmcService.master?.fmgc.data.approachBaroMinimum.set(v); + } + }} containerStyle="width: 150px;" alignText="flex-end" errorHandler={(e) => this.props.fmcService.master?.showFmsErrorMessage(e)} @@ -2523,19 +2535,32 @@ export class MfdFmsPerf extends FmsPage { - dataEntryFormat={new AltitudeFormat(Subject.create(0), Subject.create(maxCertifiedAlt))} + + dataEntryFormat={ + new RadioMinimumFormat(Subject.create(1), Subject.create(maxCertifiedAlt)) + } dataHandlerDuringValidation={async (v) => { - if (v === undefined) { - SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', -1); - } else if (v === null) { - SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', -2); - } else { - SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', v); + if (!this.props.fmcService.master?.fmgc.data.approachBaroMinimum.get()) { + if (v === 'NONE' || v === 'NO' || v === 'NO DH' || v === 'NODH' || v === null) { + SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', -2); + } else if (v === undefined) { + SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', -1); + } else { + SimVar.SetSimVarValue('L:AIRLINER_DECISION_HEIGHT', 'feet', v); + } } }} mandatory={Subject.create(false)} - value={this.props.fmcService.master.fmgc.data.approachRadioMinimum} + value={this.props.fmcService.master?.fmgc.data.approachRadioMinimum} + onModified={(v) => { + if (!this.props.fmcService.master?.fmgc.data.approachBaroMinimum.get()) { + if (v === 'NONE' || v === 'NO' || v === 'NO DH' || v === 'NODH' || v === null) { + this.props.fmcService.master?.fmgc.data.approachRadioMinimum.set(v); + } else { + this.props.fmcService.master?.fmgc.data.approachRadioMinimum.set(Number(v)); + } + } + }} containerStyle="width: 150px;" alignText="flex-end" errorHandler={(e) => this.props.fmcService.master?.showFmsErrorMessage(e)} diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/common/DataEntryFormats.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/common/DataEntryFormats.tsx index 9186ef2654e..da63b6889b7 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/common/DataEntryFormats.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/common/DataEntryFormats.tsx @@ -200,6 +200,53 @@ export class AltitudeFormat implements DataEntryFormat { } } +type RadioMinimumEntry = 'NONE' | 'NO' | 'NO DH' | 'NODH' | number; +export class RadioMinimumFormat implements DataEntryFormat { + public placeholder = '-----'; + + public maxDigits = 5; + + private minValue = 1; + + private maxValue = maxCertifiedAlt; + + constructor( + minValue: Subscribable = Subject.create(1), + maxValue: Subscribable = Subject.create(maxCertifiedAlt), + ) { + minValue.sub((val) => (this.minValue = val), true); + maxValue.sub((val) => (this.maxValue = val), true); + } + + public format(value: RadioMinimumEntry) { + if (value === null || value === undefined) { + return [this.placeholder, null, 'FT'] as FieldFormatTuple; + } else if (value === 'NONE' || value === 'NO' || value === 'NO DH' || value === 'NODH') { + return [value, null, null] as FieldFormatTuple; + } + return [Number(value).toFixed(0).toString(), null, 'FT'] as FieldFormatTuple; + } + + public async parse(input: string) { + if (input === '') { + return null; + } + if (input === 'NONE' || input === 'NO' || input === 'NO DH' || input === 'NODH') { + return input; + } + + const nbr = Number(input); + if (!Number.isNaN(nbr) && nbr <= this.maxValue && nbr >= this.minValue) { + return nbr; + } + if (nbr > this.maxValue || nbr < this.minValue) { + throw new FmsError(FmsErrorType.EntryOutOfRange); + } else { + throw new FmsError(FmsErrorType.FormatError); + } + } +} + /** * Unit of value: Feet (i.e. FL * 100) */