Skip to content

Commit

Permalink
[OANS] move DRY/WET lines when floating above runway, fix STOP bar bug
Browse files Browse the repository at this point in the history
  • Loading branch information
flogross89 committed Apr 10, 2024
1 parent a6cb232 commit 41ca3bb
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 45 deletions.
6 changes: 5 additions & 1 deletion fbw-a380x/src/systems/instruments/src/ND/instrument.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Clock, FsBaseInstrument, FSComponent, FsInstrument, HEventPublisher, In
import { A380EfisNdRangeValue, a380EfisRangeSettings, ArincEventBus, EfisNdMode, EfisSide } from '@flybywiresim/fbw-sdk';
import { NDComponent } from '@flybywiresim/navigation-display';
import {
a380EfisZoomRangeSettings, A380EfisZoomRangeValue, BtvSimvarPublisher, FmsOansArincProvider, FmsOansSimvarPublisher, Oanc, OANC_RENDER_HEIGHT,
a380EfisZoomRangeSettings, A380EfisZoomRangeValue, BtvArincProvider, BtvSimvarPublisher, FmsOansArincProvider, FmsOansSimvarPublisher, Oanc, OANC_RENDER_HEIGHT,
OANC_RENDER_WIDTH, OansControlEvents, ZOOM_TRANSITION_TIME_MS,
} from '@flybywiresim/oanc';

Expand Down Expand Up @@ -57,6 +57,8 @@ class NDInstrument implements FsInstrument {

private readonly btvSimvarPublisher: BtvSimvarPublisher;

private readonly btvArincProvider: BtvArincProvider;

private readonly fgDataPublisher: FGDataPublisher;

private readonly fmBusPublisher: FMBusPublisher;
Expand Down Expand Up @@ -171,6 +173,7 @@ class NDInstrument implements FsInstrument {
this.fmsOansSimvarPublisher = new FmsOansSimvarPublisher(this.bus);
this.fmsOansArincProvider = new FmsOansArincProvider(this.bus);
this.btvSimvarPublisher = new BtvSimvarPublisher(this.bus);
this.btvArincProvider = new BtvArincProvider(this.bus);
this.fgDataPublisher = new FGDataPublisher(this.bus);
this.fmBusPublisher = new FMBusPublisher(this.bus);
this.fmsSymbolsPublisher = new FmsSymbolsPublisher(this.bus, side);
Expand Down Expand Up @@ -198,6 +201,7 @@ class NDInstrument implements FsInstrument {
this.backplane.addPublisher('egpwc', this.egpwcBusPublisher);
this.backplane.addPublisher('hEvent', this.hEventPublisher);

this.backplane.addInstrument('btvArinc', this.btvArincProvider);
this.backplane.addInstrument('fms-arinc', this.fmsOansArincProvider);
this.backplane.addInstrument('clock', this.clock);

Expand Down
42 changes: 27 additions & 15 deletions fbw-common/src/systems/instruments/src/OANC/BrakeToVacateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ export class BrakeToVacateUtils<T extends number> {

private readonly groundSpeed = Arinc429Register.empty();

/** Updated during deceleration on the ground */
/** Updated during deceleration on the ground. Counted from touchdown distance (min. 400m). */
private readonly remaininingDistToExit = Subject.create<number>(0);

/** Updated during deceleration on the ground */
/** Updated during deceleration on the ground. Counted from touchdown distance (min. 400m). */
private readonly remaininingDistToRwyEnd = Subject.create<number>(0);

readonly btvRunway = Subject.create<string | null>(null);
Expand All @@ -95,13 +95,13 @@ export class BrakeToVacateUtils<T extends number> {

private btvPathGeometry: Position[];

/** Stopping distance for dry rwy conditions, in meters. Null if not set. */
/** Stopping distance for dry rwy conditions, in meters. Null if not set. Counted from touchdown distance (min. 400m). */
private readonly dryStoppingDistance = ConsumerSubject.create(null, 0);

/** Stopping distance for wet rwy conditions, in meters. Null if not set. */
/** Stopping distance for wet rwy conditions, in meters. Null if not set. Counted from touchdown distance (min. 400m). */
private readonly wetStoppingDistance = ConsumerSubject.create(null, 0);

/** Live remaining stopping distance during deceleration, in meters. Null if not set. */
/** Live remaining stopping distance during deceleration, in meters. Null if not set. Counted from actual aircraft position. */
private readonly liveStoppingDistance = ConsumerSubject.create(null, 0);

selectRunwayFromOans(runway: string, centerlineFeature: Feature<Geometry, AmdbProperties>, thresholdFeature: Feature<Geometry, AmdbProperties>) {
Expand Down Expand Up @@ -325,8 +325,20 @@ export class BrakeToVacateUtils<T extends number> {
ctx.resetTransform();
ctx.translate(this.canvasCentreX.get(), this.canvasCentreY.get());

const dryRunoverCondition = (TOUCHDOWN_ZONE_DISTANCE + this.dryStoppingDistance.get()) > this.btvRunwayLda.get();
const wetRunoverCondition = (TOUCHDOWN_ZONE_DISTANCE + this.wetStoppingDistance.get()) > this.btvRunwayLda.get();
const radioAlt1 = Arinc429Word.fromSimVarValue('L:A32NX_RA_1_RADIO_ALTITUDE');
const radioAlt2 = Arinc429Word.fromSimVarValue('L:A32NX_RA_2_RADIO_ALTITUDE');
const radioAlt = radioAlt1.isFailureWarning() || radioAlt1.isNoComputedData() ? radioAlt2 : radioAlt1;

// Below 600ft RA, if somewhere on approach, update DRY/WET lines according to predicted touchdown point
const dryWetLinesAreUpdating = radioAlt.valueOr(1000) <= 600;

// Aircraft distance after threshold
const isPastThreshold = this.remaininingDistToRwyEnd.get() < this.btvRunwayLda.get();
const aircraftDistFromThreshold = pointDistance(this.btvThresholdPosition[0], this.btvThresholdPosition[1], this.aircraftPpos[0], this.aircraftPpos[1]);
// As soon as aircraft passes the touchdown zone distance, draw DRY and WET stop bars from there
const touchdownDistance = (dryWetLinesAreUpdating && isPastThreshold && aircraftDistFromThreshold > TOUCHDOWN_ZONE_DISTANCE) ? aircraftDistFromThreshold : TOUCHDOWN_ZONE_DISTANCE;
const dryRunoverCondition = (touchdownDistance + this.dryStoppingDistance.get()) > this.btvRunwayLda.get();
const wetRunoverCondition = (touchdownDistance + this.wetStoppingDistance.get()) > this.btvRunwayLda.get();

const latDistance = 27.5 / this.getZoomLevelInverseScale();
const strokeWidth = 3.5 / this.getZoomLevelInverseScale();
Expand All @@ -335,7 +347,7 @@ export class BrakeToVacateUtils<T extends number> {
if (this.dryStoppingDistance.get() > 0 && !this.aircraftOnGround.get()) {
const dryStopLinePoint = fractionalPointAlongLine(this.btvThresholdPosition[0], this.btvThresholdPosition[1],
this.btvOppositeThresholdPosition[0], this.btvOppositeThresholdPosition[1],
(TOUCHDOWN_ZONE_DISTANCE + this.dryStoppingDistance.get()) / this.btvRunwayLda.get());
(touchdownDistance + this.dryStoppingDistance.get()) / this.btvRunwayLda.get());

const dryP1 = [
latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) + dryStopLinePoint[0],
Expand Down Expand Up @@ -376,7 +388,7 @@ export class BrakeToVacateUtils<T extends number> {
if (this.wetStoppingDistance.get() > 0 && !this.aircraftOnGround.get()) {
const wetStopLinePoint = fractionalPointAlongLine(this.btvThresholdPosition[0], this.btvThresholdPosition[1],
this.btvOppositeThresholdPosition[0], this.btvOppositeThresholdPosition[1],
(TOUCHDOWN_ZONE_DISTANCE + this.wetStoppingDistance.get()) / this.btvRunwayLda.get());
(touchdownDistance + this.wetStoppingDistance.get()) / this.btvRunwayLda.get());

const wetP1 = [
latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) + wetStopLinePoint[0],
Expand Down Expand Up @@ -423,14 +435,14 @@ export class BrakeToVacateUtils<T extends number> {
this.labelManager.labels.push(wetLabel);
}

// On ground & above 20kts: STOP line
if (this.liveStoppingDistance.get() > 0 && this.aircraftOnGround.get() && this.groundSpeed.value > 20) {
// On ground & above 25kts: STOP line
if (this.liveStoppingDistance.get() > 0 && this.aircraftOnGround.get() && this.groundSpeed.value > 25) {
const liveRunOverCondition = this.remaininingDistToRwyEnd.get() - this.liveStoppingDistance.get() <= 0;
const distFromThreshold = pointDistance(this.btvThresholdPosition[0], this.btvThresholdPosition[1], this.aircraftPpos[0], this.aircraftPpos[1]);
const stoppingDistanceToDraw = liveRunOverCondition ? (this.remaininingDistToRwyEnd.get() + 200) : this.liveStoppingDistance.get();
const stopLinePoint = fractionalPointAlongLine(this.aircraftPpos[0], this.aircraftPpos[1],
// If runover predicted, draw stop bar a little behind the runway end
const stoppingDistanceToDraw = liveRunOverCondition ? (this.remaininingDistToRwyEnd.get() + 100) : this.liveStoppingDistance.get();
const stopLinePoint = fractionalPointAlongLine(this.btvThresholdPosition[0], this.btvThresholdPosition[1],
this.btvOppositeThresholdPosition[0], this.btvOppositeThresholdPosition[1],
(distFromThreshold - TOUCHDOWN_ZONE_DISTANCE + stoppingDistanceToDraw) / this.btvRunwayLda.get());
(aircraftDistFromThreshold + stoppingDistanceToDraw) / this.btvRunwayLda.get());

const stopP1 = [
latDistance * Math.cos((180 - this.btvRunwayBearingTrue.get()) * MathUtils.DEGREES_TO_RADIANS) + stopLinePoint[0],
Expand Down
32 changes: 4 additions & 28 deletions fbw-common/src/systems/instruments/src/OANC/BtvPublisher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: GPL-3.0

import { EventBus, Instrument, SimVarDefinition, SimVarPublisher, SimVarValueType } from '@microsoft/msfs-sdk';
import { Arinc429SignStatusMatrix, Arinc429Word, ArincEventBus } from 'index-no-react';
import { Arinc429Word, ArincEventBus } from 'index-no-react';

export interface BtvData {
/** (BTV -> OANS) Estimated runway occupancy time (ROT), in seconds. */
Expand Down Expand Up @@ -64,39 +64,15 @@ export class BtvArincProvider implements Instrument {
const subscriber = this.bus.getSubscriber<BtvData>();

subscriber.on('btvRotRaw').whenChanged().handle((w) => {
// Workaround if plain value was transmitted instead of Arinc429Word
if (Math.abs(w) < 10000) {
const newW = Arinc429Word.empty();
newW.ssm = w > 0 ? Arinc429SignStatusMatrix.NormalOperation : Arinc429SignStatusMatrix.NoComputedData;
newW.value = w;
publisher.pub('btvRot', newW);
} else {
publisher.pub('btvRot', new Arinc429Word(w));
}
publisher.pub('btvRot', new Arinc429Word(w));
});

subscriber.on('btvTurnAroundIdleReverseRaw').whenChanged().handle((w) => {
// Workaround if plain value was transmitted instead of Arinc429Word
if (Math.abs(w) < 10000) {
const newW = Arinc429Word.empty();
newW.ssm = w > 0 ? Arinc429SignStatusMatrix.NormalOperation : Arinc429SignStatusMatrix.NoComputedData;
newW.value = w;
publisher.pub('btvTurnAroundIdleReverse', newW);
} else {
publisher.pub('btvTurnAroundIdleReverse', new Arinc429Word(w));
}
publisher.pub('btvTurnAroundIdleReverse', new Arinc429Word(w));
});

subscriber.on('btvTurnAroundMaxReverseRaw').whenChanged().handle((w) => {
// Workaround if plain value was transmitted instead of Arinc429Word
if (Math.abs(w) < 10000) {
const newW = Arinc429Word.empty();
newW.ssm = w > 0 ? Arinc429SignStatusMatrix.NormalOperation : Arinc429SignStatusMatrix.NoComputedData;
newW.value = w;
publisher.pub('btvTurnAroundMaxReverse', newW);
} else {
publisher.pub('btvTurnAroundMaxReverse', new Arinc429Word(w));
}
publisher.pub('btvTurnAroundMaxReverse', new Arinc429Word(w));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class RoseModeUnderlay extends DisplayComponent<RoseModeOverlayProps> {
/>
</g>

<rect x={212} y={538} width={41} height={21} class="BackgroundFill" />
<rect x={212} y={538} width={this.props.oansRange.map((rng) => ((rng / 2).toString().length === 4 ? 55 : 41))} height={21} class="BackgroundFill" />
<text x={212} y={556} class="Cyan" font-size={22}>
{this.props.oansRange.map((range) => range / 2)}
</text>
Expand Down

0 comments on commit 41ca3bb

Please sign in to comment.