Skip to content

Commit

Permalink
perf: optimize pfd and simconnect requests (#7835)
Browse files Browse the repository at this point in the history
* fix: use more efficient simconnect period where needed

* fix: wrong order of request

* some pfd optimizations

* fix: a380 fadec + reg is only needed

* fix some display bugs

* some cleanup

* format

* fixes

* remove unwanted code

* some fixes

* improve visilbiility computation

* use mappedsubject directly

* fix visibility

* simplify condition

Co-authored-by: BBK <22713769+BlueberryKing@users.noreply.github.com>

* streamline usage of Arinc429WordData

* update package lock to be consistent

* use sub for vspeedneedle

* fix null instance

---------

Co-authored-by: BBK <22713769+BlueberryKing@users.noreply.github.com>
  • Loading branch information
Saschl and BlueberryKing authored Jul 23, 2023
1 parent 8d382d7 commit ee021e3
Show file tree
Hide file tree
Showing 20 changed files with 171 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-3.0

import { ClockEvents, DisplayComponent, FSComponent, Subject, Subscribable, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { Arinc429Word, Arinc429WordData } from '@flybywiresim/fbw-sdk';
import { VerticalMode } from '@shared/autopilot';
import { Arinc429RegisterSubject } from 'instruments/src/MsfsAvionicsCommon/Arinc429RegisterSubject';
import { PFDSimvars } from './shared/PFDSimvarPublisher';
Expand Down Expand Up @@ -665,7 +665,7 @@ class AltimeterIndicator extends DisplayComponent<AltimeterIndicatorProps> {
}

interface MetricAltIndicatorState {
altitude: Arinc429Word;
altitude: Arinc429WordData;
targetAlt: number;
altitudeColor: TargetAltitudeColor;
metricAltToggle: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-3.0

import { DisplayComponent, FSComponent, Subject, Subscribable, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { Arinc429Register, Arinc429Word, Arinc429WordData } from '@flybywiresim/fbw-sdk';
import { getDisplayIndex } from 'instruments/src/PFD/PFD';
import { FlightPathDirector } from './FlightPathDirector';
import { FlightPathVector } from './FlightPathVector';
Expand All @@ -18,7 +18,7 @@ interface AttitudeIndicatorFixedUpperProps {
export class AttitudeIndicatorFixedUpper extends DisplayComponent<AttitudeIndicatorFixedUpperProps> {
private roll = new Arinc429Word(0);

private pitch = new Arinc429Word(0);
private pitch: Arinc429WordData = Arinc429Register.empty();

private visibilitySub = Subject.create('hidden');

Expand Down Expand Up @@ -94,7 +94,7 @@ interface AttitudeIndicatorFixedCenterProps {
export class AttitudeIndicatorFixedCenter extends DisplayComponent<AttitudeIndicatorFixedCenterProps> {
private roll = new Arinc429Word(0);

private pitch = new Arinc429Word(0);
private pitch: Arinc429WordData = Arinc429Register.empty();

private visibilitySub = Subject.create('hidden');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
//
// SPDX-License-Identifier: GPL-3.0

import { ClockEvents, DisplayComponent, FSComponent, Subject, Subscribable, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Register, Arinc429Word } from '@flybywiresim/fbw-sdk';
import { ClockEvents, ConsumerSubject, DisplayComponent, FSComponent, MappedSubject, Subject, Subscribable, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Word, Arinc429WordData } from '@flybywiresim/fbw-sdk';

import { Arinc429RegisterSubject } from 'instruments/src/MsfsAvionicsCommon/Arinc429RegisterSubject';
import { DmcLogicEvents } from '../MsfsAvionicsCommon/providers/DmcPublisher';
Expand All @@ -18,6 +18,7 @@ import { Arinc429Values } from './shared/ArincValueProvider';
import { HorizontalTape } from './HorizontalTape';
import { getDisplayIndex } from './PFD';
import { ArincEventBus } from '../MsfsAvionicsCommon/ArincEventBus';
import { Arinc429ConsumerSubject } from '../MsfsAvionicsCommon/Arinc429ConsumerSubject';

const DisplayRange = 35;
const DistanceSpacing = 15;
Expand All @@ -26,67 +27,52 @@ const ValueSpacing = 10;
class HeadingBug extends DisplayComponent<{ bus: ArincEventBus, isCaptainSide: boolean, yOffset: Subscribable<number> }> {
private isActive = false;

private selectedHeading = 0;
private selectedHeading = Subject.create(0);

private heading = Arinc429Register.empty();;
private heading = Arinc429ConsumerSubject.create(null);

private horizonHeadingBug = FSComponent.createRef<SVGGElement>();
private attitude = Arinc429ConsumerSubject.create(null);

private yOffset = 0;
private fdActive = ConsumerSubject.create(null, true);

private calculateAndSetOffset() {
const headingDelta = getSmallestAngle(this.selectedHeading, this.heading.value);
private horizonHeadingBug = FSComponent.createRef<SVGGElement>();

private readonly visibilitySub = MappedSubject.create(([heading, attitude, fdActive, selectedHeading]) => {
const headingDelta = getSmallestAngle(selectedHeading, heading.value);
const offset = headingDelta * DistanceSpacing / ValueSpacing;
const inRange = Math.abs(offset) <= DisplayRange + 10;
return !fdActive && attitude.isNormalOperation() && heading.isNormalOperation() && inRange;
}, this.heading, this.attitude, this.fdActive, this.selectedHeading);

if (Math.abs(offset) <= DisplayRange + 10) {
this.horizonHeadingBug.instance.classList.remove('HiddenElement');
this.horizonHeadingBug.instance.style.transform = `translate3d(${offset}px, ${this.yOffset}px, 0px)`;
} else {
this.horizonHeadingBug.instance.classList.add('HiddenElement');
private readonly headingBugSubject = MappedSubject.create(([heading, selectedHeading, yOffset, visible]) => {
if (visible) {
const headingDelta = getSmallestAngle(selectedHeading, heading.value);

const offset = headingDelta * DistanceSpacing / ValueSpacing;

return `transform: translate3d(${offset}px, ${yOffset}px, 0px)`;
}
}
return '';
}, this.heading, this.selectedHeading, this.props.yOffset, this.visibilitySub)

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

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

sub.on('selectedHeading').whenChanged().handle((s) => {
this.selectedHeading = s;
if (this.isActive) {
this.calculateAndSetOffset();
}
});
this.heading.setConsumer(sub.on('heading').withArinc429Precision(2));

sub.on('heading').handle((h) => {
this.heading.value = h.value;
this.heading.ssm = h.ssm;
if (this.isActive) {
this.calculateAndSetOffset();
}
});

sub.on(this.props.isCaptainSide ? 'fd1Active' : 'fd2Active').whenChanged().handle((fd) => {
this.isActive = !fd;
if (this.isActive) {
this.horizonHeadingBug.instance.classList.remove('HiddenElement');
} else {
this.horizonHeadingBug.instance.classList.add('HiddenElement');
}
sub.on('selectedHeading').whenChanged().handle((s) => {
this.selectedHeading.set(s);
});

this.props.yOffset.sub((yOffset) => {
this.yOffset = yOffset;
if (this.isActive) {
this.calculateAndSetOffset();
}
});
this.attitude.setConsumer(sub.on('pitchAr'));
this.fdActive.setConsumer(sub.on(this.props.isCaptainSide ? 'fd1Active' : 'fd2Active').whenChanged());
}

render(): VNode {
return (
<g ref={this.horizonHeadingBug} id="HorizonHeadingBug">
<g ref={this.horizonHeadingBug} id="HorizonHeadingBug" style={this.headingBugSubject} visibility={this.visibilitySub.map((v) => (v ? 'inherit' : 'hidden'))}>
<path class="ThickOutline" d="m68.906 80.823v-9.0213" />
<path class="ThickStroke Cyan" d="m68.906 80.823v-9.0213" />
</g>
Expand Down Expand Up @@ -122,32 +108,28 @@ export class Horizon extends DisplayComponent<HorizonProps> {
const apfd = this.props.bus.getArincSubscriber<Arinc429Values>();

apfd.on('pitchAr').withArinc429Precision(3).handle((pitch) => {
const multiplier = 1000;
const currentValueAtPrecision = Math.round(pitch.value * multiplier) / multiplier;
if (pitch.isNormalOperation()) {
this.pitchGroupRef.instance.style.display = 'block';

this.pitchGroupRef.instance.style.transform = `translate3d(0px, ${calculateHorizonOffsetFromPitch(currentValueAtPrecision)}px, 0px)`;
this.pitchGroupRef.instance.style.transform = `translate3d(0px, ${calculateHorizonOffsetFromPitch(pitch.value)}px, 0px)`;
} else {
this.pitchGroupRef.instance.style.display = 'none';
}
const yOffset = Math.max(Math.min(calculateHorizonOffsetFromPitch(currentValueAtPrecision), 31.563), -31.563);
const yOffset = Math.max(Math.min(calculateHorizonOffsetFromPitch(pitch.value), 31.563), -31.563);
this.yOffset.set(yOffset);
});

apfd.on('rollAr').withArinc429Precision(2).handle((roll) => {
const multiplier = 100;
const currentValueAtPrecision = Math.round(roll.value * multiplier) / multiplier;
if (roll.isNormalOperation()) {
this.rollGroupRef.instance.style.display = 'block';

this.rollGroupRef.instance.setAttribute('transform', `rotate(${-currentValueAtPrecision} 68.814 80.730)`);
this.rollGroupRef.instance.setAttribute('transform', `rotate(${-roll.value} 68.814 80.730)`);
} else {
this.rollGroupRef.instance.style.display = 'none';
}
});

apfd.on('fcdcDiscreteWord1').handle((fcdcWord1) => {
apfd.on('fcdcDiscreteWord1').whenArinc429SsmChanged().handle((fcdcWord1) => {
const isNormalLawActive = fcdcWord1.getBitValue(11) && !fcdcWord1.isFailureWarning();

this.pitchProtSymbolLower.instance.style.display = isNormalLawActive ? 'block' : 'none';
Expand Down Expand Up @@ -588,9 +570,9 @@ class SideslipIndicator extends DisplayComponent<SideslipIndicatorProps> {
}

class RisingGround extends DisplayComponent<{ bus: ArincEventBus, filteredRadioAltitude: Subscribable<number> }> {
private radioAlt = new Arinc429Word(0);
private radioAlt: Arinc429WordData = new Arinc429Word(0);

private lastPitch = new Arinc429Word(0);
private lastPitch: Arinc429WordData = new Arinc429Word(0);

private horizonGroundRectangle = FSComponent.createRef<SVGGElement>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,11 @@ class Drum extends DisplayComponent<DrumProperties> {
private digitRefElements: NodeReference<SVGTextElement>[] = [];

private buildElements(amount: number) {
const highestPosition = Math.round((this.position + this.props.displayRange) / this.props.valueSpacing) * this.props.valueSpacing;

const highestValue = Math.round((this.value + this.props.displayRange) / this.props.valueSpacing) * this.props.valueSpacing;

const graduationElements: SVGTextElement[] = [];

for (let i = 0; i < amount; i++) {
const elementPosition = highestPosition - i * this.props.valueSpacing;
const offset = -elementPosition * this.props.distanceSpacing / this.props.valueSpacing;

let elementVal = highestValue - i * this.props.valueSpacing;
if (!this.showZero && elementVal === 0) {
elementVal = NaN;
Expand All @@ -246,13 +241,13 @@ class Drum extends DisplayComponent<DrumProperties> {
const digitRef = FSComponent.createRef<SVGTextElement>();

if (this.props.type === 'hundreds') {
graduationElements.push(<text ref={digitRef} transform={`translate(0 ${offset})`} class={`FontLargest MiddleAlign ${this.color}`} x="11.631" y="7.1" />);
graduationElements.push(<text ref={digitRef} style="transform: rotate3d(0px, 0px, 0px)" class={`FontLargest MiddleAlign ${this.color}`} x="11.631" y="7.1" />);
} else if (this.props.type === 'thousands') {
graduationElements.push(<text ref={digitRef} transform={`translate(0 ${offset})`} class={`FontLargest MiddleAlign ${this.color}`} x="7.18" y="7.1" />);
graduationElements.push(<text ref={digitRef} style="transform: rotate3d(0px, 0px, 0px)" class={`FontLargest MiddleAlign ${this.color}`} x="7.18" y="7.1" />);
} else if (this.props.type === 'ten-thousands') {
graduationElements.push(<text ref={digitRef} transform={`translate(0 ${offset})`} class={`FontLargest MiddleAlign ${this.color}`} x="2.498" y="7.1" />);
graduationElements.push(<text ref={digitRef} style="transform: rotate3d(0px, 0px, 0px)" class={`FontLargest MiddleAlign ${this.color}`} x="2.498" y="7.1" />);
} else if (this.props.type === 'tens') {
graduationElements.push(<text ref={digitRef} transform={`translate(0 ${offset})`} class={`FontSmallest MiddleAlign ${this.color}`} x="4.5894" y="8.9133" />);
graduationElements.push(<text ref={digitRef} style="transform: rotate3d(0px, 0px, 0px)" class={`FontSmallest MiddleAlign ${this.color}`} x="4.5894" y="8.9133" />);
}
this.digitRefElements.push(digitRef);
}
Expand All @@ -261,9 +256,7 @@ class Drum extends DisplayComponent<DrumProperties> {
}

private getOffset(position: number) {
const className = `translate(0 ${position * this.props.distanceSpacing / this.props.valueSpacing})`;

this.gRef.instance.setAttribute('transform', className);
this.gRef.instance.style.transform = `translate3d(0px, ${position * this.props.distanceSpacing / this.props.valueSpacing}px, 0px)`;
}

private updateValue() {
Expand Down
16 changes: 8 additions & 8 deletions fbw-a32nx/src/systems/instruments/src/PFD/FMA.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ export class FMA extends DisplayComponent<{ bus: ArincEventBus, isAttExcessive:

private fwcFlightPhase = 0;

private firstBorderRef = FSComponent.createRef<SVGPathElement>();
private firstBorderSub = Subject.create('');

private secondBorderRef = FSComponent.createRef<SVGPathElement>();
private secondBorderSub = Subject.create('');

private AB3Message = Subject.create(false);

Expand Down Expand Up @@ -97,8 +97,8 @@ export class FMA extends DisplayComponent<{ bus: ArincEventBus, isAttExcessive:
}

this.AB3Message.set(AB3Message);
this.firstBorderRef.instance.setAttribute('d', firstBorder);
this.secondBorderRef.instance.setAttribute('d', secondBorder);
this.firstBorderSub.set(firstBorder);
this.secondBorderSub.set(secondBorder);
}

onAfterRender(node: VNode): void {
Expand Down Expand Up @@ -149,7 +149,7 @@ export class FMA extends DisplayComponent<{ bus: ArincEventBus, isAttExcessive:
this.handleFMABorders();
});

sub.on('fcdcDiscreteWord1').whenChanged().handle((fcdcDiscreteWord1) => {
sub.on('fcdcDiscreteWord1').atFrequency(1).handle((fcdcDiscreteWord1) => {
this.fcdcDiscreteWord1 = fcdcDiscreteWord1;
this.handleFMABorders();
});
Expand All @@ -168,8 +168,8 @@ export class FMA extends DisplayComponent<{ bus: ArincEventBus, isAttExcessive:
return (
<g id="FMA">
<g class="NormalStroke Grey">
<path ref={this.firstBorderRef} />
<path ref={this.secondBorderRef} />
<path d={this.firstBorderSub} />
<path d={this.secondBorderSub} />
<path d="m102.52 0.33732v20.864" />
<path d="m133.72 0.33732v20.864" />
</g>
Expand Down Expand Up @@ -1324,7 +1324,7 @@ class BC3Cell extends DisplayComponent<{ isAttExcessive: Subscribable<boolean>,
this.fillBC3Cell();
});

sub.on('fcdcDiscreteWord1').whenChanged().handle((fcdcDiscreteWord1) => {
sub.on('fcdcDiscreteWord1').atFrequency(1).handle((fcdcDiscreteWord1) => {
this.fcdcDiscreteWord1 = fcdcDiscreteWord1;
this.fillBC3Cell();
});
Expand Down
10 changes: 5 additions & 5 deletions fbw-a32nx/src/systems/instruments/src/PFD/FlightPathDirector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-3.0

import { ClockEvents, DisplayComponent, FSComponent, Subscribable, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { Arinc429Word, Arinc429WordData } from '@flybywiresim/fbw-sdk';
import { getDisplayIndex } from './PFD';
import { calculateHorizonOffsetFromPitch } from './PFDUtils';
import { Arinc429Values } from './shared/ArincValueProvider';
Expand All @@ -14,10 +14,10 @@ const DistanceSpacing = 15;
const ValueSpacing = 10;

interface FlightPathVectorData {
roll: Arinc429Word;
pitch: Arinc429Word;
fpa: Arinc429Word;
da: Arinc429Word;
roll: Arinc429WordData;
pitch: Arinc429WordData;
fpa: Arinc429WordData;
da: Arinc429WordData;
activeVerticalMode: number;
activeLateralMode: number;
fdRoll: number;
Expand Down
10 changes: 5 additions & 5 deletions fbw-a32nx/src/systems/instruments/src/PFD/FlightPathVector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-3.0

import { ClockEvents, DisplayComponent, FSComponent, VNode } from '@microsoft/msfs-sdk';
import { Arinc429Word } from '@flybywiresim/fbw-sdk';
import { Arinc429Word, Arinc429WordData } from '@flybywiresim/fbw-sdk';
import { ArincEventBus } from '../MsfsAvionicsCommon/ArincEventBus';
import { calculateHorizonOffsetFromPitch } from './PFDUtils';
import { Arinc429Values } from './shared/ArincValueProvider';
Expand All @@ -13,10 +13,10 @@ const DistanceSpacing = 15;
const ValueSpacing = 10;

interface FlightPathVectorData {
roll: Arinc429Word;
pitch: Arinc429Word;
fpa: Arinc429Word;
da: Arinc429Word;
roll: Arinc429WordData;
pitch: Arinc429WordData;
fpa: Arinc429WordData;
da: Arinc429WordData;
}

export class FlightPathVector extends DisplayComponent<{ bus: ArincEventBus }> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ export class HeadingOfftape extends DisplayComponent<{ bus: ArincEventBus, faile
onAfterRender(node: VNode): void {
super.onAfterRender(node);

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

sub.on('heading').handle((word) => {
sub.on('heading').withArinc429Precision(2).handle((word) => {
this.heading.set(word.value);

if (word.isNormalOperation()) {
Expand Down
Loading

0 comments on commit ee021e3

Please sign in to comment.