diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 5f1f0f6fcb3..7780ae9465d 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -146,6 +146,7 @@ 1. [A380X/MFD] Updated disabled input field styling - @jet2code (john) 1. [A380X/FMS] Add page scroll via soft keys & individual scroll via KCCU on MFD F-PLN - @BravoMike99 (bruno_pt99) 1. [A32NX/FMS] Added nav database swap confirmation - @tracernz (Mike) +1. [A380X/FMS] Add basic FIX INFO functionality - @Benjozork (Benjamin Dupont) ## 0.12.0 diff --git a/fbw-a32nx/src/systems/fmgc/src/NavigationDatabase.ts b/fbw-a32nx/src/systems/fmgc/src/NavigationDatabase.ts index 9a5326b0884..a9647f4be8d 100644 --- a/fbw-a32nx/src/systems/fmgc/src/NavigationDatabase.ts +++ b/fbw-a32nx/src/systems/fmgc/src/NavigationDatabase.ts @@ -49,7 +49,7 @@ export class NavigationDatabase { return this.backendDatabase.getWaypoints([ident]); } - async searchAllFix(ident: string): Promise<(Waypoint | VhfNavaid | NdbNavaid)[]> { + async searchAllFix(ident: string): Promise { return [ ...(await this.backendDatabase.getWaypoints([ident])), ...(await this.backendDatabase.getNavaids([ident])), diff --git a/fbw-a32nx/src/systems/fmgc/src/efis/EfisSymbols.ts b/fbw-a32nx/src/systems/fmgc/src/efis/EfisSymbols.ts index ad2bb74ef2d..6b6b5bc024a 100644 --- a/fbw-a32nx/src/systems/fmgc/src/efis/EfisSymbols.ts +++ b/fbw-a32nx/src/systems/fmgc/src/efis/EfisSymbols.ts @@ -801,7 +801,7 @@ export class EfisSymbols { // FP fix info if (flightPlan instanceof FlightPlan && flightPlan.index === FlightPlanIndex.Active && !isAlternate) { - for (let i = 0; i < 4; i++) { + for (let i = 0; i < flightPlan.fixInfos.length; i++) { const fixInfo = flightPlan.fixInfos[i]; if (!fixInfo) { diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/DataManager.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/DataManager.ts index ea3a3dcd9b9..beebd74ee80 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/DataManager.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/DataManager.ts @@ -4,7 +4,7 @@ import { Fix, NXDataStore, Waypoint } from '@flybywiresim/fbw-sdk'; import { FmsError, FmsErrorType } from '@fmgc/FmsError'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { WaypointFactory } from '@fmgc/flightplanning/waypoints/WaypointFactory'; import { Coordinates } from 'msfs-geo'; @@ -61,7 +61,7 @@ export class DataManager { private latLonExtendedFormat = false; - constructor(private fmc: DisplayInterface) { + constructor(private fmc: FmsDisplayInterface) { // we keep these in localStorage so they live for the same length of time as the flightplan (that they could appear in) // if the f-pln is not stored there anymore we can delete this const stored = localStorage.getItem(DataManager.STORED_WP_KEY); diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/ObservableFlightPlanManager.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/ObservableFlightPlanManager.ts new file mode 100644 index 00000000000..58af7df9eae --- /dev/null +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/ObservableFlightPlanManager.ts @@ -0,0 +1,32 @@ +import { EventBus, Subject, Subscribable, Subscription } from '@microsoft/msfs-sdk'; +import { FlightPlanEvents } from '@fmgc/flightplanning/sync/FlightPlanEvents'; +import { FlightPlanInterface } from '@fmgc/flightplanning/FlightPlanInterface'; +import { FlightPlanIndex } from '@fmgc/flightplanning/FlightPlanManager'; + +export class ObservableFlightPlanManager { + private readonly subscriptions: Subscription[] = []; + + private readonly flightPlanEventsSubscriber = this.bus.getSubscriber(); + + constructor( + private readonly bus: EventBus, + private readonly flightPlanInterface: FlightPlanInterface, + ) { + this.initialize(); + } + + private initialize(): void { + this._temporaryPlanExists.set(this.flightPlanInterface.hasTemporary); + + this.subscriptions.push( + this.flightPlanEventsSubscriber.on('flightPlanManager.create').handle((event) => { + if (event.planIndex === FlightPlanIndex.Temporary) { + this._temporaryPlanExists.set(true); + } + }), + ); + } + + private readonly _temporaryPlanExists = Subject.create(false); + public readonly temporaryPlanExists: Subscribable = this._temporaryPlanExists; +} diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.spec.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.spec.ts index 40b7f5c12dc..5321cd84b76 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.spec.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.spec.ts @@ -7,16 +7,16 @@ import { jest } from '@jest/globals'; import { FlightPlanService } from '@fmgc/flightplanning/FlightPlanService'; import { setupNavigraphDatabase } from '@fmgc/flightplanning/test/Database'; import { WaypointEntryUtils } from '@fmgc/flightplanning/WaypointEntryUtils'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { DatabaseItem, Waypoint } from '@flybywiresim/fbw-sdk'; import { FmsErrorType } from '@fmgc/FmsError'; import { Coordinates, placeBearingDistance, placeBearingIntersection } from 'msfs-geo'; import { WaypointFactory } from '@fmgc/flightplanning/waypoints/WaypointFactory'; -import { DataInterface } from './interface/DataInterface'; +import { FmsDataInterface } from './interface/FmsDataInterface'; jest.setTimeout(120_000); -const fms: DisplayInterface & DataInterface = { +const fms: FmsDisplayInterface & FmsDataInterface = { showFmsErrorMessage(errorType: FmsErrorType) { console.error(FmsErrorType[errorType]); }, diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.ts index 225c0bb98ee..f13fe3a9e08 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/WaypointEntryUtils.ts @@ -6,9 +6,9 @@ import { Fix, NdbNavaid, VhfNavaid, Waypoint } from '@flybywiresim/fbw-sdk'; import { NavigationDatabaseService } from '@fmgc/flightplanning/NavigationDatabaseService'; import { WaypointFactory } from '@fmgc/flightplanning/waypoints/WaypointFactory'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { Coordinates } from 'msfs-geo'; -import { DataInterface } from '@fmgc/flightplanning/interface/DataInterface'; +import { FmsDataInterface } from '@fmgc/flightplanning/interface/FmsDataInterface'; import { FmsError, FmsErrorType } from '@fmgc/FmsError'; export class WaypointEntryUtils { @@ -22,7 +22,7 @@ export class WaypointEntryUtils { * @returns a waypoint, or `undefined` if the operation is cancelled */ static async getOrCreateWaypoint( - fms: DataInterface & DisplayInterface, + fms: FmsDataInterface & FmsDisplayInterface, place: string, stored: boolean, ident?: string, @@ -53,7 +53,7 @@ export class WaypointEntryUtils { /** * Parse a place string into a position */ - static async parsePlace(fms: DisplayInterface & DataInterface, place: string): Promise { + static async parsePlace(fms: FmsDisplayInterface & FmsDataInterface, place: string): Promise { if (WaypointEntryUtils.isRunwayFormat(place)) { return WaypointEntryUtils.parseRunway(place); } @@ -157,7 +157,7 @@ export class WaypointEntryUtils { * * @returns place and magnetic bearing */ - static async parsePbx(fms: DisplayInterface & DataInterface, str: string): Promise<[Fix, number, Fix, number]> { + static async parsePbx(fms: FmsDisplayInterface & FmsDataInterface, str: string): Promise<[Fix, number, Fix, number]> { const pbx = str.match(/^([^\-/]+)-([0-9]{1,3})\/([^\-/]+)-([0-9]{1,3})$/); if (pbx === null) { @@ -183,7 +183,7 @@ export class WaypointEntryUtils { * @param {string} s */ static async parsePbd( - fms: DataInterface & DisplayInterface, + fms: FmsDataInterface & FmsDisplayInterface, s: string, ): Promise<[wp: Fix, trueBearing: number, dist: number]> { const [place, brg, dist] = WaypointEntryUtils.splitPbd(s); diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DataInterface.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDataInterface.ts similarity index 95% rename from fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DataInterface.ts rename to fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDataInterface.ts index 0e2f4f92504..8c3a4a6dd57 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DataInterface.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDataInterface.ts @@ -7,7 +7,7 @@ import { Coordinates, DegreesMagnetic } from 'msfs-geo'; import { Fix } from '@flybywiresim/fbw-sdk'; import { PilotWaypoint } from '@fmgc/flightplanning/DataManager'; -export interface DataInterface { +export interface FmsDataInterface { createLatLonWaypoint(coordinates: Coordinates, stored: boolean, ident?: string): PilotWaypoint; createPlaceBearingPlaceBearingWaypoint( diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DisplayInterface.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDisplayInterface.ts similarity index 97% rename from fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DisplayInterface.ts rename to fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDisplayInterface.ts index 55e46c8e023..940ac5f6cf2 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/DisplayInterface.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/interface/FmsDisplayInterface.ts @@ -6,7 +6,7 @@ import { DatabaseItem, Waypoint } from '@flybywiresim/fbw-sdk'; import { FmsErrorType } from '@fmgc/FmsError'; -export interface DisplayInterface { +export interface FmsDisplayInterface { /** * Called when a flight plan uplink is in progress */ diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FixInfo.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FixInfo.ts index cc55adb044d..27485425f00 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FixInfo.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FixInfo.ts @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: GPL-3.0 -import { NdbNavaid, VhfNavaid, Waypoint } from '@flybywiresim/fbw-sdk'; +import { Fix } from '@flybywiresim/fbw-sdk'; export interface FixInfoRadial { trueBearing: DegreesTrue; @@ -25,15 +25,15 @@ export interface FixInfoRadius { */ export class FixInfoEntry implements FixInfoData { /** The fix concerned by the fix info */ - public readonly fix: Waypoint | VhfNavaid | NdbNavaid; + public fix: Fix; /** The radii contained in the fix info */ - public readonly radii?: FixInfoRadius[]; + public radii?: FixInfoRadius[]; /** The radials contained in the fix ino */ - public readonly radials?: FixInfoRadial[]; + public radials?: FixInfoRadial[]; - constructor(fix: Waypoint | VhfNavaid | NdbNavaid, radii?: FixInfoRadius[], radials?: FixInfoRadial[]) { + constructor(fix: Fix, radii?: FixInfoRadius[], radials?: FixInfoRadial[]) { this.fix = fix; this.radii = radii; this.radials = radials; @@ -50,7 +50,7 @@ export class FixInfoEntry implements FixInfoData { export interface FixInfoData { /** The fix concerned by the fix info */ - fix: Waypoint | VhfNavaid | NdbNavaid; + fix: Fix; /** The radii contained in the fix info */ radii?: FixInfoRadius[]; diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FlightPlan.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FlightPlan.ts index bd4bd9b7cc0..1c91e55c661 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FlightPlan.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FlightPlan.ts @@ -343,10 +343,15 @@ export class FlightPlan

(); + + constructor( + private readonly bus: EventBus, + private readonly flightPlanInterface: FlightPlanInterface, + private readonly index: number, + ) { + const plan = flightPlanInterface.get(index); + + this.initializeFromPlan(plan); + } + + public destroy(): void { + for (const subscription of this.subscriptions) { + subscription.destroy(); + } + } + + private initializeFromPlan(plan: BaseFlightPlan): void { + if (plan instanceof FlightPlan) { + for (let i = 1; i < plan.fixInfos.length; i++) { + const fix = plan.fixInfos[i] ?? null; + + this._fixInfos[i].set(fix); + } + } + + this.subscriptions.push( + this.flightPlanEventsSubscriber.on('flightPlan.setFixInfoEntry').handle((event) => { + if (event.planIndex !== plan.index) { + return; + } + + const subject = this._fixInfos[event.index]; + + subject.set(event.fixInfo ?? null); + }), + ); + } + + private readonly _fixInfos: Record<1 | 2 | 3 | 4, Subject> = { + 1: this.createFixInfoSubject(), + 2: this.createFixInfoSubject(), + 3: this.createFixInfoSubject(), + 4: this.createFixInfoSubject(), + } as const; + public readonly fixInfos: Record<1 | 2 | 3 | 4, Subscribable> = this._fixInfos; + + private createFixInfoSubject(): Subject { + const equalityFunc = (a: FixInfoData | null, b: FixInfoData | null): boolean => { + if ((a === null) !== (b === null)) { + return false; + } + + if (a?.fix.databaseId !== b?.fix.databaseId) { + return false; + } + + for (let i = 0; i < a?.radials.length; i++) { + const aRadial = a?.radials[i]; + const bRadial = b?.radials[i]; + + if (aRadial !== bRadial) { + return false; + } + } + + for (let i = 0; i < a?.radii.length; i++) { + const aRadius = a?.radii[i]; + const bRadius = b?.radii[i]; + + if (aRadius !== bRadius) { + return false; + } + } + + return true; + }; + + return Subject.create(null, equalityFunc); + } +} diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/ReadonlyFlightPlan.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/ReadonlyFlightPlan.ts index ad76795122b..6296f7867a2 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/ReadonlyFlightPlan.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/ReadonlyFlightPlan.ts @@ -28,11 +28,11 @@ export interface ReadonlyFlightPlan { get version(): number; - get originLeg(): ReadonlyFlightPlanElement; + get originLeg(): ReadonlyFlightPlanElement | undefined; get originLegIndex(): number; - get destinationLeg(): ReadonlyFlightPlanElement; + get destinationLeg(): ReadonlyFlightPlanElement | undefined; get destinationLegIndex(): number; @@ -58,11 +58,14 @@ export interface ReadonlyFlightPlan { get arrivalEnrouteTransition(): ProcedureTransition | undefined; - get arrival(): Arrival | undefined; + /** + * The arrival procedure. If it's `undefined`, it means that no arrival is set. If it's `null`, it means that the "NO STAR" is explicitly selected. + */ + get arrival(): Arrival | undefined | null; get arrivalRunwayTransition(): ProcedureTransition | undefined; - get approachVia(): ProcedureTransition | undefined; + get approachVia(): ProcedureTransition | undefined | null; get approach(): Approach | undefined; diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/CoRouteUplinkAdapter.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/CoRouteUplinkAdapter.ts index 51c0b0c944a..789bbe4e1a4 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/CoRouteUplinkAdapter.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/CoRouteUplinkAdapter.ts @@ -10,9 +10,9 @@ import { FlightPlanIndex } from '@fmgc/flightplanning/FlightPlanManager'; import { NavigationDatabaseService } from '@fmgc/flightplanning/NavigationDatabaseService'; import { Fix, Airway } from '@flybywiresim/fbw-sdk'; import { Coordinates, distanceTo } from 'msfs-geo'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import type { Fix as CoRouteFix } from '@simbridge/Coroute/Fix'; -import { DataInterface } from '../interface/DataInterface'; +import { FmsDataInterface } from '../interface/FmsDataInterface'; import { FmsErrorType } from '@fmgc/FmsError'; export interface OfpRoute { @@ -104,7 +104,7 @@ type CoRoute = { export class CoRouteUplinkAdapter { static async uplinkFlightPlanFromCoRoute( - fms: DataInterface & DisplayInterface, + fms: FmsDataInterface & FmsDisplayInterface, flightPlanService: FlightPlanService, ofp: CoRoute, ) { diff --git a/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/SimBriefUplinkAdapter.ts b/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/SimBriefUplinkAdapter.ts index dfb428a346b..8046d5f6be4 100644 --- a/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/SimBriefUplinkAdapter.ts +++ b/fbw-a32nx/src/systems/fmgc/src/flightplanning/uplink/SimBriefUplinkAdapter.ts @@ -10,14 +10,14 @@ import { FlightPlanIndex } from '@fmgc/flightplanning/FlightPlanManager'; import { NavigationDatabaseService } from '@fmgc/flightplanning/NavigationDatabaseService'; import { Airway, Fix } from '@flybywiresim/fbw-sdk'; import { Coordinates, distanceTo } from 'msfs-geo'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { FlightPlanPerformanceData } from '@fmgc/flightplanning/plans/performance/FlightPlanPerformanceData'; import { FmsErrorType } from '@fmgc/FmsError'; import { ISimbriefData, simbriefDataParser, } from '../../../../../../../fbw-common/src/systems/instruments/src/EFB/Apis/Simbrief'; -import { DataInterface } from '../interface/DataInterface'; +import { FmsDataInterface } from '../interface/FmsDataInterface'; const SIMBRIEF_API_URL = 'https://www.simbrief.com/api/xml.fetcher.php?json=1'; @@ -114,7 +114,7 @@ export interface SimBriefUplinkOptions { export class SimBriefUplinkAdapter { static async uplinkFlightPlanFromSimbrief

( - fms: DataInterface & DisplayInterface, + fms: FmsDataInterface & FmsDisplayInterface, flightPlanService: FlightPlanService

, ofp: ISimbriefData, options: SimBriefUplinkOptions, diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FlightManagementComputer.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FlightManagementComputer.ts index b64cce86105..fad073742b5 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FlightManagementComputer.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FlightManagementComputer.ts @@ -51,7 +51,7 @@ import { } from 'instruments/src/MFD/shared/NXSystemMessages'; import { PilotWaypoint } from '@fmgc/flightplanning/DataManager'; import { distanceTo, Coordinates } from 'msfs-geo'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { MfdDisplayInterface } from 'instruments/src/MFD/MFD'; import { FmcIndex } from 'instruments/src/MFD/FMC/FmcServiceInterface'; import { FmsErrorType } from '@fmgc/FmsError'; @@ -76,13 +76,13 @@ export interface FmsErrorMessage { export class FlightManagementComputer implements FmcInterface { protected subs = [] as Subscription[]; - #mfdReference: (DisplayInterface & MfdDisplayInterface) | null; + #mfdReference: (FmsDisplayInterface & MfdDisplayInterface) | null; get mfdReference() { return this.#mfdReference; } - set mfdReference(value: (DisplayInterface & MfdDisplayInterface) | null) { + set mfdReference(value: (FmsDisplayInterface & MfdDisplayInterface) | null) { this.#mfdReference = value; if (value) { @@ -214,7 +214,7 @@ export class FlightManagementComputer implements FmcInterface { operatingMode: FmcOperatingModes, private readonly bus: EventBus, private readonly fmcInop: Subscribable, - mfdReference: (DisplayInterface & MfdDisplayInterface) | null, + mfdReference: (FmsDisplayInterface & MfdDisplayInterface) | null, ) { this.#operatingMode = operatingMode; this.#mfdReference = mfdReference; diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcInterface.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcInterface.ts index 526bb770245..b9d046ebb0e 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcInterface.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcInterface.ts @@ -1,6 +1,6 @@ import { FmsErrorType } from '@fmgc/FmsError'; -import { DataInterface } from '@fmgc/flightplanning/interface/DataInterface'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDataInterface } from '@fmgc/flightplanning/interface/FmsDataInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { DataManager, FlightPlanIndex, FlightPlanService, GuidanceController } from '@fmgc/index'; import { NavaidTuner } from '@fmgc/navigation/NavaidTuner'; import { NavigationProvider } from '@fmgc/navigation/NavigationProvider'; @@ -34,7 +34,7 @@ export interface FlightPhaseManagerProxyInterface { * Handles requests inside each FlightManagementComputer (FMC). * DisplayInterface shouldn't be here, but WaypointEntryUtils requires on parameter with both DisplayInterface and DataInterface */ -export interface FmcInterface extends FlightPhaseManagerProxyInterface, DataInterface, DisplayInterface { +export interface FmcInterface extends FlightPhaseManagerProxyInterface, FmsDataInterface, FmsDisplayInterface { /** * Which operation mode is FMC in? Can be master, slave or standby. */ @@ -44,8 +44,8 @@ export interface FmcInterface extends FlightPhaseManagerProxyInterface, DataInte /** * Mfd reference, used for navigating to pages and opening prompts */ - get mfdReference(): (DisplayInterface & MfdDisplayInterface) | null; - set mfdReference(value: DisplayInterface & MfdDisplayInterface); + get mfdReference(): (FmsDisplayInterface & MfdDisplayInterface) | null; + set mfdReference(value: FmsDisplayInterface & MfdDisplayInterface); /** * FlightPlanService interface diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcService.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcService.ts index 9bd874c151c..4caec85a96e 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcService.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcService.ts @@ -1,4 +1,4 @@ -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { ConsumerSubject, EventBus, @@ -69,7 +69,7 @@ export class FmcService implements FmcServiceInterface { constructor( private readonly bus: EventBus, - private readonly mfdReference: (DisplayInterface & MfdDisplayInterface) | null, + private readonly mfdReference: (FmsDisplayInterface & MfdDisplayInterface) | null, private readonly fmcAFailed: Subscribable, private readonly fmcBFailed: Subscribable, private readonly fmcCFailed: Subscribable, @@ -92,7 +92,7 @@ export class FmcService implements FmcServiceInterface { return this.fmc.find((it) => it.operatingMode === FmcOperatingModes.Standby) ?? null; } - createFmc(mfdReference: (DisplayInterface & MfdDisplayInterface) | null): void { + createFmc(mfdReference: (FmsDisplayInterface & MfdDisplayInterface) | null): void { // Only FMC-A is operative for now, this takes up enough resources already // Before more FMC can be added, they have to be synced this.fmc.push( @@ -119,7 +119,7 @@ export class FmcService implements FmcServiceInterface { return this.fmc[forFmcIndex]; } - setMfdReference(forFmcIndex: FmcIndex, mfd: DisplayInterface & MfdDisplayInterface) { + setMfdReference(forFmcIndex: FmcIndex, mfd: FmsDisplayInterface & MfdDisplayInterface) { if (this.fmc[forFmcIndex] === undefined) { return; } diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcServiceInterface.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcServiceInterface.ts index 27c2b0d8eeb..fe1807272ac 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcServiceInterface.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcServiceInterface.ts @@ -1,4 +1,4 @@ -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { FmcInterface } from 'instruments/src/MFD/FMC/FmcInterface'; import { MfdDisplayInterface } from 'instruments/src/MFD/MFD'; @@ -30,7 +30,7 @@ export interface FmcServiceInterface { /** * Instantiate FMCs. Currently, only FMC-A is instantiated. */ - createFmc(mfdReference: DisplayInterface & MfdDisplayInterface): void; + createFmc(mfdReference: FmsDisplayInterface & MfdDisplayInterface): void; /** * Check whether given FMC is instantiated @@ -45,5 +45,5 @@ export interface FmcServiceInterface { /** * Sets mfd reference for given FMC, used for navigating to pages and opening prompts */ - setMfdReference(forFmcIndex: FmcIndex, mfd: DisplayInterface & MfdDisplayInterface): void; + setMfdReference(forFmcIndex: FmcIndex, mfd: FmsDisplayInterface & MfdDisplayInterface): void; } diff --git a/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx b/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx index cd60b114481..2dcc1981fda 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/MFD.tsx @@ -23,7 +23,7 @@ import { MfdMsgList } from 'instruments/src/MFD/pages/FMS/MfdMsgList'; import { ActiveUriInformation, MfdUiService } from 'instruments/src/MFD/pages/common/MfdUiService'; import { MfdFmsFplnDuplicateNames } from 'instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFplnDuplicateNames'; import { headerForSystem, pageForUrl } from 'instruments/src/MFD/MfdPageDirectory'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { FmsErrorType } from '@fmgc/FmsError'; import { FmcServiceInterface } from 'instruments/src/MFD/FMC/FmcServiceInterface'; import { CdsDisplayUnit, DisplayUnitID } from '../MsfsAvionicsCommon/CdsDisplayUnit'; @@ -40,7 +40,7 @@ export const getDisplayIndex = () => { export interface AbstractMfdPageProps extends ComponentProps { pageTitle?: string; bus: EventBus; - mfd: DisplayInterface & MfdDisplayInterface; + mfd: FmsDisplayInterface & MfdDisplayInterface; fmcService: FmcServiceInterface; } @@ -61,7 +61,10 @@ export interface MfdDisplayInterface { openMessageList(): void; } -export class MfdComponent extends DisplayComponent implements DisplayInterface, MfdDisplayInterface { +export class MfdComponent + extends DisplayComponent + implements FmsDisplayInterface, MfdDisplayInterface +{ private readonly sub = this.props.bus.getSubscriber(); #uiService = new MfdUiService(this.props.captOrFo, this.props.bus); diff --git a/fbw-a380x/src/systems/instruments/src/MFD/MfdPageDirectory.tsx b/fbw-a380x/src/systems/instruments/src/MFD/MfdPageDirectory.tsx index fde3a77b18b..19d1ead9442 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/MfdPageDirectory.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/MfdPageDirectory.tsx @@ -25,18 +25,19 @@ import { FcuBkupHeader } from 'instruments/src/MFD/pages/common/FcuBkupHeader'; import { FmsHeader } from 'instruments/src/MFD/pages/common/FmsHeader'; import { SurvHeader } from 'instruments/src/MFD/pages/common/SurvHeader'; import { FmcServiceInterface } from 'instruments/src/MFD/FMC/FmcServiceInterface'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { MfdDisplayInterface } from 'instruments/src/MFD/MFD'; import { MfdUiService } from 'instruments/src/MFD/pages/common/MfdUiService'; import { MfdFmsDataDebug } from 'instruments/src/MFD/pages/FMS/DATA/MfdFmsDataDebug'; import { MfdSurvControls } from 'instruments/src/MFD/pages/SURV/MfdSurvControls'; +import { MfdFmsFplnFixInfo } from './pages/FMS/F-PLN/MfdFmsFplnFixInfo'; import { MfdSurvStatusSwitching } from 'instruments/src/MFD/pages/SURV/MfdSurvStatusSwitching'; import { MfdFmsDataAirport } from 'instruments/src/MFD/pages/FMS/DATA/MfdFmsDataAirport'; export function pageForUrl( url: string, bus: EventBus, - mfd: DisplayInterface & MfdDisplayInterface, + mfd: FmsDisplayInterface & MfdDisplayInterface, fmcService: FmcServiceInterface, ): VNode { switch (url) { @@ -87,6 +88,8 @@ export function pageForUrl( case 'fms/sec2/f-pln-hold': case 'fms/sec3/f-pln-hold': return ; + case 'fms/active/f-pln-fix-info': + return ; case 'fms/position/irs': return ; case 'fms/position/navaids': @@ -115,7 +118,7 @@ export function pageForUrl( export function headerForSystem( sys: string, - mfd: DisplayInterface & MfdDisplayInterface, + mfd: FmsDisplayInterface & MfdDisplayInterface, atcCallsign: Subscribable, activeFmsSource: Subscribable<'FMS 1' | 'FMS 2' | 'FMS 1-C' | 'FMS 2-C'>, uiService: MfdUiService, diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/DestinationWindow.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/DestinationWindow.tsx index 87bd8027230..dbd6d6cccc5 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/DestinationWindow.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/DestinationWindow.tsx @@ -3,13 +3,13 @@ import '../../common/style.scss'; import { Button } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/Button'; import { InputField } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/InputField'; import { AirportFormat } from 'instruments/src/MFD/pages/common/DataEntryFormats'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { MfdDisplayInterface } from 'instruments/src/MFD/MFD'; import { FmcServiceInterface } from 'instruments/src/MFD/FMC/FmcServiceInterface'; interface DestinationWindowProps extends ComponentProps { fmcService: FmcServiceInterface; - mfd: DisplayInterface & MfdDisplayInterface; + mfd: FmsDisplayInterface & MfdDisplayInterface; visible: Subject; } export class DestinationWindow extends DisplayComponent { diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/FplnRevisionsMenu.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/FplnRevisionsMenu.tsx index 2ddda72d32a..6f97a24f3df 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/FplnRevisionsMenu.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/FplnRevisionsMenu.tsx @@ -4,6 +4,8 @@ import { SegmentClass } from '@fmgc/flightplanning/segments/SegmentClass'; import { FlightPlanIndex } from '@fmgc/index'; import { MfdFmsFpln } from 'instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFpln'; import { ContextMenuElement } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/ContextMenu'; +import { BitFlags } from '@microsoft/msfs-sdk'; +import { FlightPlanLegFlags } from '@fmgc/flightplanning/legs/FlightPlanLeg'; export enum FplnRevisionsMenuType { Waypoint, @@ -27,6 +29,13 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): const previousLeg = fpln.loadedFlightPlan?.maybeElementAt(legIndex - 1); const revisedLeg = fpln.loadedFlightPlan?.elementAt(legIndex); + const isFromLeg = legIndex === fpln.loadedFlightPlan?.fromLegIndex; + const isLegTerminatingAtDatabaseFix = + revisedLeg && + !revisedLeg.isDiscontinuity && + revisedLeg.isXF() && + !BitFlags.isAny(revisedLeg.flags, FlightPlanLegFlags.DirectToTurningPoint); + return [ { name: 'FROM P.POS DIR TO', @@ -35,8 +44,8 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): legIndex >= (fpln.loadedFlightPlan?.firstMissedApproachLegIndex ?? Infinity) || planIndex === FlightPlanIndex.Temporary || [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type) || - revisedLeg?.isDiscontinuity || - !revisedLeg?.isXF(), + isFromLeg || + !isLegTerminatingAtDatabaseFix, onPressed: () => { const ppos = fpln.props.fmcService.master?.navigation.getPpos(); if (ppos) { @@ -63,6 +72,7 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): disabled: [FplnRevisionsMenuType.Runway || FplnRevisionsMenuType.TooSteepPath].includes(type) || (revisedLeg?.isDiscontinuity && !previousLeg?.isDiscontinuity && previousLeg?.isVectors()) || + isFromLeg || // TODO allow in HDG/TRK planIndex === FlightPlanIndex.Temporary, onPressed: () => { fpln.props.fmcService.master?.flightPlanService.deleteElementAt(legIndex, false, planIndex, altnFlightPlan); @@ -88,7 +98,10 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): }, { name: 'HOLD', - disabled: [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), + disabled: + [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type) || + isFromLeg || + !isLegTerminatingAtDatabaseFix, onPressed: async () => { if (revisedLeg && !revisedLeg.isDiscontinuity && !revisedLeg.isHX()) { const alt = revisedLeg.definition.altitude1 @@ -130,9 +143,10 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): [ FplnRevisionsMenuType.Runway || FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath, ].includes(type) || - revisedLeg?.isDiscontinuity || - revisedLeg?.waypointDescriptor === WaypointDescriptor.Airport || - revisedLeg?.waypointDescriptor === WaypointDescriptor.Runway, + isFromLeg || + !isLegTerminatingAtDatabaseFix || + revisedLeg.waypointDescriptor === WaypointDescriptor.Airport || + revisedLeg.waypointDescriptor === WaypointDescriptor.Runway, onPressed: () => { fpln.props.fmcService.master?.flightPlanService.startAirwayEntry(legIndex); fpln.props.mfd.uiService.navigateTo(`fms/${fpln.props.mfd.uiService.activeUri.get().category}/f-pln-airways`); @@ -147,13 +161,16 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): ? 'DELETE OVERFLY *' : 'OVERFLY *', disabled: - altnFlightPlan || [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), + altnFlightPlan || + [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type) || + isFromLeg || + !isLegTerminatingAtDatabaseFix, onPressed: () => fpln.props.fmcService.master?.flightPlanService.toggleOverfly(legIndex, planIndex, altnFlightPlan), }, { name: 'ENABLE ALTN *', - disabled: false, + disabled: !revisedLeg || revisedLeg.isDiscontinuity, onPressed: () => { fpln.props.fmcService.master?.flightPlanService.enableAltn(legIndex, planIndex); fpln.props.fmcService.master?.acInterface.updateOansAirports(); @@ -161,13 +178,15 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): }, { name: 'NEW DEST', - disabled: false, + disabled: isFromLeg || !isLegTerminatingAtDatabaseFix, onPressed: () => fpln.openNewDestWindow(), }, { name: 'CONSTRAINTS', disabled: - altnFlightPlan || [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), + altnFlightPlan || + !isLegTerminatingAtDatabaseFix || + [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), onPressed: () => fpln.props.mfd.uiService.navigateTo( `fms/${fpln.props.mfd.uiService.activeUri.get().category}/f-pln-vert-rev/alt`, @@ -187,7 +206,9 @@ export function getRevisionsMenu(fpln: MfdFmsFpln, type: FplnRevisionsMenuType): { name: 'STEP ALTs', disabled: - altnFlightPlan || [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), + altnFlightPlan || + !isLegTerminatingAtDatabaseFix || + [FplnRevisionsMenuType.Discontinuity || FplnRevisionsMenuType.TooSteepPath].includes(type), onPressed: () => fpln.props.mfd.uiService.navigateTo( `fms/${fpln.props.mfd.uiService.activeUri.get().category}/f-pln-vert-rev/step-alts`, diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/InsertNextWptFrom.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/InsertNextWptFrom.tsx index 94e802d3b50..506069a3870 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/InsertNextWptFrom.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/InsertNextWptFrom.tsx @@ -15,7 +15,7 @@ import { DropdownMenu } from 'instruments/src/MsfsAvionicsCommon/UiWidgets/Dropd import { WaypointEntryUtils } from '@fmgc/flightplanning/WaypointEntryUtils'; import { FmcServiceInterface } from 'instruments/src/MFD/FMC/FmcServiceInterface'; import { FlightPlanIndex } from '@fmgc/index'; -import { DisplayInterface } from '@fmgc/flightplanning/interface/DisplayInterface'; +import { FmsDisplayInterface } from '@fmgc/flightplanning/interface/FmsDisplayInterface'; import { MfdDisplayInterface } from 'instruments/src/MFD/MFD'; import { FmsError } from '@fmgc/FmsError'; @@ -25,7 +25,7 @@ export type NextWptInfo = { }; interface InsertNextWptFromWindowProps extends ComponentProps { fmcService: FmcServiceInterface; - mfd: DisplayInterface & MfdDisplayInterface; + mfd: FmsDisplayInterface & MfdDisplayInterface; availableWaypoints: SubscribableArray; visible: Subject; contentContainerStyle?: string; diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFpln.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFpln.tsx index 0d1f2912a3c..2afda3448d0 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFpln.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/F-PLN/MfdFmsFpln.tsx @@ -981,13 +981,14 @@ export class MfdFmsFpln extends FmsPage { componentIfFalse={<>} />