Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(a380x/mfd): basic FIX INFO functionality and lat rev menu fixes #9471

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
1e8811a
feat: initial commit
Benjozork Nov 9, 2024
c64dce5
chore: rename FMS interface types
Benjozork Nov 10, 2024
e5aea55
fix: button regression
Benjozork Nov 10, 2024
90c2bf1
fix: multiple fix info corrections
Benjozork Nov 10, 2024
1e78df7
fix: allowed revisions
Benjozork Nov 10, 2024
1d339a3
fix: magvar, error handling, jsdoc
Benjozork Nov 10, 2024
5b00fec
fix: NOT IN DATABASE and validation flashing
Benjozork Nov 11, 2024
b7e7140
feat: predictions layout
Benjozork Nov 11, 2024
f1b0de7
feat: abeam button
Benjozork Nov 11, 2024
fe51b83
fix: make other F-PLN INFO options disabled
Benjozork Nov 11, 2024
7832634
docs: update FIX INFO page status
Benjozork Nov 11, 2024
c843959
fix: more revision availability fixes
Benjozork Nov 11, 2024
df8a44d
Merge remote-tracking branch 'origin/master' into feat/a380-fix-info
Benjozork Nov 29, 2024
4e7034a
fix: accuracy improvements
Benjozork Nov 30, 2024
5b7d4bc
feat: color fix-info page in yellow when tmpy exists
Benjozork Nov 30, 2024
ba46a38
fix: InputField initial alignment
Benjozork Nov 30, 2024
38aab20
feat: return/tmpy-fpln button
Benjozork Nov 30, 2024
a5dbbef
Merge branch 'master' into feat/a380-fix-info
Benjozork Jan 5, 2025
d38e2b6
chore: move import
Benjozork Jan 5, 2025
a2432a1
chore: remove unnecessary ?.
Benjozork Jan 5, 2025
a9cd915
docs: add changelog
Benjozork Jan 5, 2025
7226555
Merge branch 'master' into feat/a380-fix-info
Benjozork Jan 18, 2025
dbeb3f6
fix: fix info 4
Benjozork Jan 18, 2025
ad33062
fix: clearing fix info fields
Benjozork Jan 18, 2025
adc3200
Merge branch 'master' into feat/a380-fix-info
Benjozork Jan 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fbw-a32nx/src/systems/fmgc/src/NavigationDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class NavigationDatabase {
return this.backendDatabase.getWaypoints([ident]);
}

async searchAllFix(ident: string): Promise<(Waypoint | VhfNavaid | NdbNavaid)[]> {
async searchAllFix(ident: string): Promise<Fix[]> {
return [
...(await this.backendDatabase.getWaypoints([ident])),
...(await this.backendDatabase.getNavaids([ident])),
Expand Down
4 changes: 2 additions & 2 deletions fbw-a32nx/src/systems/fmgc/src/efis/EfisSymbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -813,8 +813,8 @@ export class EfisSymbols<T extends number> {
ident: fixInfo.fix.ident,
location: fixInfo.fix.location,
type: NdSymbolTypeFlags.FixInfo,
radials: fixInfo.radials.map((it) => it.trueBearing),
radii: fixInfo.radii.map((it) => it.radius),
radials: fixInfo?.radials.map((it) => it.trueBearing),
radii: fixInfo?.radii.map((it) => it.radius),
Benjozork marked this conversation as resolved.
Show resolved Hide resolved
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions fbw-a32nx/src/systems/fmgc/src/flightplanning/DataManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<FlightPlanEvents>();

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<boolean> = this._temporaryPlanExists;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -53,7 +53,7 @@ export class WaypointEntryUtils {
/**
* Parse a place string into a position
*/
static async parsePlace(fms: DisplayInterface & DataInterface, place: string): Promise<Fix> {
static async parsePlace(fms: FmsDisplayInterface & FmsDataInterface, place: string): Promise<Fix> {
if (WaypointEntryUtils.isRunwayFormat(place)) {
return WaypointEntryUtils.parseRunway(place);
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
12 changes: 6 additions & 6 deletions fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FixInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// SPDX-License-Identifier: GPL-3.0

import { NdbNavaid, VhfNavaid, Waypoint } from '@flybywiresim/fbw-sdk';
import { AnyFix } from '@flybywiresim/fbw-sdk';

export interface FixInfoRadial {
trueBearing: DegreesTrue;
Expand All @@ -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: AnyFix;

/** 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: AnyFix, radii?: FixInfoRadius[], radials?: FixInfoRadial[]) {
this.fix = fix;
this.radii = radii;
this.radials = radials;
Expand All @@ -50,7 +50,7 @@ export class FixInfoEntry implements FixInfoData {

export interface FixInfoData {
/** The fix concerned by the fix info */
fix: Waypoint | VhfNavaid | NdbNavaid;
fix: AnyFix;

/** The radii contained in the fix info */
radii?: FixInfoRadius[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ export class FlightPlan<P extends FlightPlanPerformanceData = FlightPlanPerforma
setFixInfoEntry(index: 1 | 2 | 3 | 4, fixInfo: FixInfoData | null, notify = true): void {
const planFixInfo = this.fixInfos as FixInfoEntry[];

planFixInfo[index] = fixInfo ? new FixInfoEntry(fixInfo.fix, fixInfo.radii, fixInfo.radials) : undefined;
planFixInfo[index] = fixInfo ? new FixInfoEntry(fixInfo.fix, fixInfo?.radii, fixInfo?.radials) : undefined;

if (notify) {
this.sendEvent('flightPlan.setFixInfoEntry', { planIndex: this.index, forAlternate: false, index, fixInfo });
Expand All @@ -362,7 +362,12 @@ export class FlightPlan<P extends FlightPlanPerformanceData = FlightPlanPerforma
}

if (notify) {
this.sendEvent('flightPlan.setFixInfoEntry', { planIndex: this.index, forAlternate: false, index, fixInfo: res });
this.sendEvent('flightPlan.setFixInfoEntry', {
planIndex: this.index,
forAlternate: false,
index,
fixInfo: res.clone(),
});
}

this.incrementVersion();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { EventBus, Subject, Subscribable, Subscription } from '@microsoft/msfs-sdk';

import { BaseFlightPlan } from './BaseFlightPlan';
import { FlightPlanInterface } from '../FlightPlanInterface';
import { FixInfoData } from './FixInfo';
import { FlightPlan } from './FlightPlan';
import { FlightPlanEvents } from '@fmgc/flightplanning/sync/FlightPlanEvents';

/**
* A flight plan wrapper which exposes subcribable elements and properties.
*
* **Note:** Add flight plan elements here as you need them reactively in MFD/ND UI.
*/
export class ObservableFlightPlan {
private readonly subscriptions: Subscription[] = [];

private readonly flightPlanEventsSubscriber = this.bus.getSubscriber<FlightPlanEvents>();

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<FixInfoData | null>> = {
1: this.createFixInfoSubject(),
2: this.createFixInfoSubject(),
3: this.createFixInfoSubject(),
4: this.createFixInfoSubject(),
} as const;
public readonly fixInfos: Record<1 | 2 | 3 | 4, Subscribable<FixInfoData | null>> = this._fixInfos;

private createFixInfoSubject(): Subject<FixInfoData | null> {
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<FixInfoData | null>(null, equalityFunc);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -104,7 +104,7 @@ type CoRoute = {

export class CoRouteUplinkAdapter {
static async uplinkFlightPlanFromCoRoute(
fms: DataInterface & DisplayInterface,
fms: FmsDataInterface & FmsDisplayInterface,
flightPlanService: FlightPlanService,
ofp: CoRoute,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -114,7 +114,7 @@ export interface SimBriefUplinkOptions {

export class SimBriefUplinkAdapter {
static async uplinkFlightPlanFromSimbrief<P extends FlightPlanPerformanceData>(
fms: DataInterface & DisplayInterface,
fms: FmsDataInterface & FmsDisplayInterface,
flightPlanService: FlightPlanService<P>,
ofp: ISimbriefData,
options: SimBriefUplinkOptions,
Expand Down
Loading
Loading