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/pfd): Add FCU ALT ABOVE/BELOW A/C FMA messages #9674

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
94 changes: 90 additions & 4 deletions fbw-a380x/src/systems/instruments/src/PFD/FMA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@
/* eslint-disable no-constant-condition */
import {
ComponentProps,
ConsumerSubject,
DisplayComponent,
EventBus,
FSComponent,
MappedSubject,
Subject,
Subscribable,
VNode,
} from '@microsoft/msfs-sdk';
import { ArmedLateralMode, isArmed, LateralMode, VerticalMode } from '@shared/autopilot';
import { Arinc429Values } from './shared/ArincValueProvider';
import { PFDSimvars } from './shared/PFDSimvarPublisher';
import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { SimplaneValues } from 'instruments/src/MsfsAvionicsCommon/providers/SimplaneValueProvider';
import { Arinc429ConsumerSubject, Arinc429Word } from '@flybywiresim/fbw-sdk';

abstract class ShowForSecondsComponent<T extends ComponentProps> extends DisplayComponent<T> {
private timeout: number = 0;
Expand Down Expand Up @@ -69,6 +72,38 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc

private AB3Message = Subject.create(false);

private isUnrestrictedClimbDescent: number = 0;
Pruznak marked this conversation as resolved.
Show resolved Hide resolved

private readonly sub = this.props.bus.getSubscriber<PFDSimvars & Arinc429Values & SimplaneValues>();

private readonly selectedFpa = ConsumerSubject.create(this.sub.on('selectedFpa'), 0);

private readonly selectedVs = ConsumerSubject.create(this.sub.on('selectedVs'), 0);

private readonly selectedAltitude = ConsumerSubject.create(this.sub.on('selectedAltitude'), 0);

private readonly altitude = Arinc429ConsumerSubject.create(this.sub.on('altitudeAr'));

private readonly activeVerticalModeConsumer = ConsumerSubject.create(this.sub.on('activeVerticalMode'), 0);

private readonly UnrestrictedClimbDescent = MappedSubject.create(
Pruznak marked this conversation as resolved.
Show resolved Hide resolved
([selectedFpa, selectedVs, altitude, selectedAltitude, activeVerticalMode]) => {
if (activeVerticalMode === VerticalMode.FPA || activeVerticalMode === VerticalMode.VS) {
if ((selectedFpa > 0 || selectedVs > 0) && selectedAltitude < altitude.value) {
return 1;
} else if ((selectedFpa < 0 || selectedVs < 0) && selectedAltitude > altitude.value) {
return 2;
}
}
return 0;
},
this.selectedFpa,
this.selectedVs,
this.altitude,
this.selectedAltitude,
this.activeVerticalModeConsumer,
) as Subscribable<number>;
Pruznak marked this conversation as resolved.
Show resolved Hide resolved

private handleFMABorders() {
const sharedModeActive =
this.activeLateralMode === 32 ||
Expand All @@ -83,6 +118,7 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
this.trkFpaDeselected.get(),
this.tcasRaInhibited.get(),
this.tdReached,
this.isUnrestrictedClimbDescent,
Pruznak marked this conversation as resolved.
Show resolved Hide resolved
)[0] !== null;

const engineMessage = this.athrModeMessage;
Expand Down Expand Up @@ -115,7 +151,7 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
onAfterRender(node: VNode): void {
super.onAfterRender(node);

const sub = this.props.bus.getSubscriber<PFDSimvars & Arinc429Values>();
const sub = this.props.bus.getSubscriber<Arinc429Values & PFDSimvars & SimplaneValues>();

this.props.isAttExcessive.sub((_a) => {
this.handleFMABorders();
Expand Down Expand Up @@ -175,6 +211,11 @@ export class FMA extends DisplayComponent<{ bus: EventBus; isAttExcessive: Subsc
this.tdReached = tdr;
this.handleFMABorders();
});

this.UnrestrictedClimbDescent.sub((val) => {
this.isUnrestrictedClimbDescent = val;
this.handleFMABorders();
});
}

render(): VNode {
Expand Down Expand Up @@ -916,7 +957,7 @@ class B1Cell extends ShowForSecondsComponent<CellProps> {
});

sub
.on('apVsSelected')
.on('selectedVs')
.whenChanged()
.handle((svs) => {
this.selectedVS = svs;
Expand Down Expand Up @@ -1298,6 +1339,7 @@ const getBC3Message = (
trkFpaDeselectedTCAS: boolean,
tcasRaInhibited: boolean,
tdReached: boolean,
unrestrictedClimbDescent: number,
) => {
const armedVerticalBitmask = armedVerticalMode;
const TCASArmed = (armedVerticalBitmask >> 6) & 1;
Expand Down Expand Up @@ -1339,6 +1381,12 @@ const getBC3Message = (
} else if (false) {
text = 'EXIT MISSED';
className = 'White';
} else if (unrestrictedClimbDescent === 1) {
text = 'FCU ALT BELOW A/C';
className = 'FontMediumSmaller White';
} else if (unrestrictedClimbDescent === 2) {
text = 'FCU ALT ABOVE A/C';
className = 'DisappearAfter10Seconds FontMediumSmaller White';
} else {
return [null, null];
}
Expand All @@ -1363,6 +1411,38 @@ class BC3Cell extends DisplayComponent<{ isAttExcessive: Subscribable<boolean>;

private tdReached = false;

private isUnrestrictedClimbDescent = 0;
Pruznak marked this conversation as resolved.
Show resolved Hide resolved

private readonly sub = this.props.bus.getSubscriber<Arinc429Values & PFDSimvars & SimplaneValues>();

private readonly selectedFpa = ConsumerSubject.create(this.sub.on('selectedFpa'), 0);

private readonly selectedVs = ConsumerSubject.create(this.sub.on('selectedVs'), 0);

private readonly selectedAltitude = ConsumerSubject.create(this.sub.on('selectedAltitude'), 0);

private readonly altitude = Arinc429ConsumerSubject.create(this.sub.on('altitudeAr'));

private readonly activeVerticalMode = ConsumerSubject.create(this.sub.on('activeVerticalMode'), 0);

private readonly UnrestrictedClimbDescent = MappedSubject.create(
([selectedFpa, selectedVs, altitude, selectedAltitude, activeVerticalMode]) => {
if (activeVerticalMode === VerticalMode.FPA || activeVerticalMode === VerticalMode.VS) {
if ((selectedFpa > 0 || selectedVs > 0) && selectedAltitude < altitude.value) {
return 1;
} else if ((selectedFpa < 0 || selectedVs < 0) && selectedAltitude > altitude.value) {
return 2;
}
}
return 0;
},
this.selectedFpa,
this.selectedVs,
this.altitude,
this.selectedAltitude,
this.activeVerticalMode,
) as Subscribable<number>;

private fillBC3Cell() {
const [text, className] = getBC3Message(
this.isAttExcessive,
Expand All @@ -1371,6 +1451,7 @@ class BC3Cell extends DisplayComponent<{ isAttExcessive: Subscribable<boolean>;
this.trkFpaDeselected,
this.tcasRaInhibited,
this.tdReached,
this.isUnrestrictedClimbDescent,
);
this.classNameSub.set(`FontMedium MiddleAlign ${className}`);
if (text !== null) {
Expand All @@ -1383,7 +1464,7 @@ class BC3Cell extends DisplayComponent<{ isAttExcessive: Subscribable<boolean>;
onAfterRender(node: VNode): void {
super.onAfterRender(node);

const sub = this.props.bus.getSubscriber<PFDSimvars>();
const sub = this.props.bus.getSubscriber<PFDSimvars & Arinc429Values & SimplaneValues>();

this.props.isAttExcessive.sub((e) => {
this.isAttExcessive = e;
Expand Down Expand Up @@ -1429,6 +1510,11 @@ class BC3Cell extends DisplayComponent<{ isAttExcessive: Subscribable<boolean>;
this.tdReached = tdr;
this.fillBC3Cell();
});

this.UnrestrictedClimbDescent.sub((val) => {
this.isUnrestrictedClimbDescent = val;
this.fillBC3Cell();
});
}

render(): VNode {
Expand Down
4 changes: 4 additions & 0 deletions fbw-a380x/src/systems/instruments/src/PFD/animations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
100% {opacity: 1}
}

@keyframes Disappear{
to {visibility: hidden}
}

.BlinkInfinite {
animation-name: blinking;
animation-duration: 1s;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface PFDSimvars {
fmaModeReversion: boolean;
fmaSpeedProtection: boolean;
AThrMode: number;
apVsSelected: number;
selectedVs: number;
approachCapability: number;
ap1Active: boolean;
ap2Active: boolean;
Expand Down Expand Up @@ -193,7 +193,7 @@ export enum PFDVars {
fmaModeReversion = 'L:A32NX_FMA_MODE_REVERSION',
fmaSpeedProtection = 'L:A32NX_FMA_SPEED_PROTECTION_MODE',
AThrMode = 'L:A32NX_AUTOTHRUST_MODE',
apVsSelected = 'L:A32NX_AUTOPILOT_VS_SELECTED',
selectedVs = 'L:A32NX_AUTOPILOT_VS_SELECTED',
approachCapability = 'L:A32NX_APPROACH_CAPABILITY',
ap1Active = 'L:A32NX_AUTOPILOT_1_ACTIVE',
ap2Active = 'L:A32NX_AUTOPILOT_2_ACTIVE',
Expand Down Expand Up @@ -361,7 +361,7 @@ export class PFDSimvarPublisher extends UpdatableSimVarPublisher<PFDSimvars> {
['fmaModeReversion', { name: PFDVars.fmaModeReversion, type: SimVarValueType.Bool }],
['fmaSpeedProtection', { name: PFDVars.fmaSpeedProtection, type: SimVarValueType.Bool }],
['AThrMode', { name: PFDVars.AThrMode, type: SimVarValueType.Number }],
['apVsSelected', { name: PFDVars.apVsSelected, type: SimVarValueType.FPM }],
['selectedVs', { name: PFDVars.selectedVs, type: SimVarValueType.FPM }],
['approachCapability', { name: PFDVars.approachCapability, type: SimVarValueType.Number }],
['ap1Active', { name: PFDVars.ap1Active, type: SimVarValueType.Bool }],
['ap2Active', { name: PFDVars.ap2Active, type: SimVarValueType.Bool }],
Expand Down
4 changes: 4 additions & 0 deletions fbw-a380x/src/systems/instruments/src/PFD/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
animation-iteration-count: 9;
}

.DisappearAfter10Seconds {
animation: Disappear 0s 10s forwards;
}

.BarAmber {
fill: $display-amber;
stroke: $display-amber;
Expand Down
Loading