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(pfd): add LS reminder indicator #9668

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
1. [A380X/ENGINES] Adjust climb thrust to be more accurate - @BlueberryKing (BlueberryKing)
1. [A380X/EWD] Show THR limit in EWD instead of N1 - @flogross89 (floridude)
1. [A380X/FLIGHT MODEL] Fix pitchup and unrecoverable stall - - @donstim (donbikes#4084)
1. [PFD] Add LS button reminder - @BravoMike99 (bruno_pt99)

## 0.12.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
Subscription,
VNode,
} from '@microsoft/msfs-sdk';
import { ArincEventBus, Arinc429RegisterSubject, MathUtils } from '@flybywiresim/fbw-sdk';
import { ArincEventBus, Arinc429RegisterSubject, MathUtils, Arinc429ConsumerSubject } from '@flybywiresim/fbw-sdk';

import { getDisplayIndex } from 'instruments/src/PFD/PFD';
import { FcuBus } from 'instruments/src/PFD/shared/FcuBusProvider';
import { Arinc429Values } from './shared/ArincValueProvider';
import { PFDSimvars } from './shared/PFDSimvarPublisher';
import { LagFilter } from './PFDUtils';
import { FmgcFlightPhase } from '@shared/flightphase';
import { FlashOneHertz } from '../MsfsAvionicsCommon/FlashingElementUtils';
import { FgBus } from './shared/FgBusProvider';

// FIXME true ref
export class LandingSystem extends DisplayComponent<{ bus: ArincEventBus; instrument: BaseInstrument }> {
Expand Down Expand Up @@ -92,6 +95,9 @@ export class LandingSystem extends DisplayComponent<{ bus: ArincEventBus; instru
d="m 114.84887,80.06669 v 1.51188 h -8.43284 v -1.51188 z"
/>
</g>
<g>
<LsReminderIndicator bus={this.props.bus} />
</g>
<g id="DeviationGroup" class={{ HiddenElement: this.lsVisible }}>
<g id="LateralDeviationGroup" class={{ HiddenElement: this.isLDevHidden }}>
<LDevIndicator bus={this.props.bus} />
Expand Down Expand Up @@ -741,3 +747,59 @@ class MarkerBeaconIndicator extends DisplayComponent<{ bus: ArincEventBus }> {
);
}
}

class LsReminderIndicator extends DisplayComponent<{ bus: ArincEventBus }> {
private readonly sub = this.props.bus.getSubscriber<PFDSimvars & FcuBus & FgBus>();

private readonly glsMlsFlsOrLocVnavInstalled = Subject.create(false);

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

private readonly fmgcFlightPhase = ConsumerSubject.create(this.sub.on('fmgcFlightPhase'), FmgcFlightPhase.Preflight);

private readonly fmgcDiscreteWord2 = Arinc429ConsumerSubject.create(this.sub.on('fmgcDiscreteWord3'));

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

private readonly landModeArmedOrActive = MappedSubject.create(
([fmgcDiscreteWord2, fmgcDiscreteWord4]) =>
fmgcDiscreteWord4.bitValueOr(14, false) || fmgcDiscreteWord2.bitValueOr(20, false),
this.fmgcDiscreteWord2,
this.fmgcDiscreteWord4,
);

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

private readonly lsPushed = this.fcuEisDiscreteWord2.map((w) => w.bitValueOr(22, false));

private readonly lsReminderVisible = MappedSubject.create(
([fwcPhase, fmgcPhase, landModeArmedOrActive, lsPushed]) => {
return (
landModeArmedOrActive &&
fmgcPhase === FmgcFlightPhase.Approach &&
!lsPushed && // TODO Check if LOC or G/S scales are invalid
fwcPhase !== 8 &&
fwcPhase !== 9 &&
fwcPhase !== 10
);
},
this.fwcFlightPhase,
this.fmgcFlightPhase,
this.landModeArmedOrActive,
this.lsPushed,
);

onAfterRender(node: VNode): void {
super.onAfterRender(node);
}

render(): VNode {
return (
<FlashOneHertz bus={this.props.bus} flashDuration={9} visible={this.lsReminderVisible}>
<text class="FontLargest Amber EndAlign" x="112.80" y="124.8">
{this.glsMlsFlsOrLocVnavInstalled.map((v) => (v ? 'LS' : 'ILS'))}
</text>
</FlashOneHertz>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { Arinc429Values } from './shared/ArincValueProvider';
import { PFDSimvars } from './shared/PFDSimvarPublisher';
import { LagFilter } from './PFDUtils';
import { FmgcFlightPhase } from '@shared/flightphase';

export class LandingSystem extends DisplayComponent<{ bus: EventBus; instrument: BaseInstrument }> {
private lsButtonPressedVisibility = false;
Expand Down Expand Up @@ -95,11 +96,14 @@ export class LandingSystem extends DisplayComponent<{ bus: EventBus; instrument:
<LocalizerIndicator bus={this.props.bus} instrument={this.props.instrument} />
<GlideSlopeIndicator bus={this.props.bus} instrument={this.props.instrument} />
<MarkerBeaconIndicator bus={this.props.bus} />
<LsReminder bus={this.props.bus} />
<LsTitle bus={this.props.bus} />
</g>

<path ref={this.gsReferenceLine} class="Yellow Fill" d="m115.52 80.067v1.5119h-8.9706v-1.5119z" />
</g>

<g>
<LsReminderIndicator bus={this.props.bus} />
</g>
<g id="DeviationGroup" ref={this.deviationGroup} style="display: none">
<g id="LateralDeviationGroup" ref={this.ldevRef} style="display: none">
<LDevIndicator bus={this.props.bus} />
Expand Down Expand Up @@ -609,14 +613,14 @@ class MarkerBeaconIndicator extends DisplayComponent<{ bus: EventBus }> {
}
}

class LsReminder extends DisplayComponent<{ bus: EventBus }> {
private readonly lsReminderRef = FSComponent.createRef<SVGTextElement>();
class LsTitle extends DisplayComponent<{ bus: EventBus }> {
private readonly lsTitle = FSComponent.createRef<SVGTextElement>();

private readonly hasLoc = ConsumerSubject.create(null, false);

private readonly lsButton = ConsumerSubject.create(null, false);

private readonly ilsReminderShown = MappedSubject.create(
private readonly ilsTitleShown = MappedSubject.create(
([hasLoc, lsButton]) => hasLoc && lsButton,
this.hasLoc,
this.lsButton,
Expand All @@ -631,20 +635,71 @@ class LsReminder extends DisplayComponent<{ bus: EventBus }> {
this.lsButton.setConsumer(sub.on(getDisplayIndex() === 2 ? 'ls2Button' : 'ls1Button').whenChanged());

// normally the ident and freq should be always displayed when an ILS freq is set, but currently it only show when we have a signal
this.ilsReminderShown.sub((it) => {
this.ilsTitleShown.sub((it) => {
if (it) {
this.lsReminderRef.instance.style.display = 'inline';
this.lsTitle.instance.style.display = 'inline';
} else {
this.lsReminderRef.instance.style.display = 'none';
this.lsTitle.instance.style.display = 'none';
}
});
}

render(): VNode {
return (
<text class="FontLargest Magenta MiddleAlign Blink9Seconds" ref={this.lsReminderRef} x="104" y="126">
<text class="FontLargest Magenta MiddleAlign Blink9Seconds" ref={this.lsTitle} x="104" y="126">
ILS
</text>
);
}
}

class LsReminderIndicator extends DisplayComponent<{ bus: EventBus }> {
private readonly sub = this.props.bus.getSubscriber<PFDSimvars>();

private readonly lsReminder = FSComponent.createRef<SVGTextElement>();

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

private readonly fmgcFlightPhase = ConsumerSubject.create(this.sub.on('fmgcFlightPhase'), FmgcFlightPhase.Preflight);

private readonly approachModePushed = ConsumerSubject.create(this.sub.on('fcuApproachModeActive'), false);

private readonly lsButton = ConsumerSubject.create(null, false);

private readonly lsReminderVisible = MappedSubject.create(
([fwcPhase, fmgcPhase, approachModePushed, lsPushed]) => {
return (
approachModePushed &&
fmgcPhase === FmgcFlightPhase.Approach &&
!lsPushed && // TODO Check if LOC or G/S scales are invalid
fwcPhase !== 10 &&
fwcPhase !== 11 &&
fwcPhase !== 12
);
},
this.fwcFlightPhase,
this.fmgcFlightPhase,
this.approachModePushed,
this.lsButton,
);

onAfterRender(node: VNode): void {
super.onAfterRender(node);
this.lsButton.setConsumer(this.sub.on(getDisplayIndex() === 2 ? 'ls2Button' : 'ls1Button'));
this.lsReminderVisible.sub((v) => {
if (v) {
this.lsReminder.instance.style.display = 'inline';
} else {
this.lsReminder.instance.style.display = 'none';
}
});
}

render(): VNode {
return (
<text class="FontLargest Amber Blink9Seconds" x="104.33" y="124.8" ref={this.lsReminder}>
LS
</text>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export interface PFDSimvars {
spoilersArmed: boolean;
fcuLeftVelocityVectorOn: boolean;
fcuRightVelocityVectorOn: boolean;
fcuApproachModeActive: boolean;
}

export enum PFDVars {
Expand Down Expand Up @@ -334,6 +335,7 @@ export enum PFDVars {
spoilersArmed = 'L:A32NX_SPOILERS_ARMED',
fcuLeftVelocityVectorOn = 'L:A380X_EFIS_L_VV_BUTTON_IS_ON',
fcuRightVelocityVectorOn = 'L:A380X_EFIS_R_VV_BUTTON_IS_ON',
fcuApproachModeActive = 'L:A32NX_FCU_APPR_MODE_ACTIVE',
}

/** A publisher to poll and publish nav/com simvars. */
Expand Down Expand Up @@ -500,6 +502,7 @@ export class PFDSimvarPublisher extends UpdatableSimVarPublisher<PFDSimvars> {
['spoilersArmed', { name: PFDVars.spoilersArmed, type: SimVarValueType.Bool }],
['fcuLeftVelocityVectorOn', { name: PFDVars.fcuLeftVelocityVectorOn, type: SimVarValueType.Bool }],
['fcuRightVelocityVectorOn', { name: PFDVars.fcuRightVelocityVectorOn, type: SimVarValueType.Bool }],
['fcuApproachModeActive', { name: PFDVars.fcuApproachModeActive, type: SimVarValueType.Bool }],
]);

public constructor(bus: EventBus) {
Expand Down
Loading