Skip to content

Commit

Permalink
feat: vertical navigation (#7080) @72b7cf8cb
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueberryKing authored and aguther committed May 9, 2022
1 parent de83217 commit 7e33c75
Show file tree
Hide file tree
Showing 87 changed files with 8,377 additions and 857 deletions.
39 changes: 39 additions & 0 deletions docs/a320-simvars.md
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,35 @@
- Bool
- Indicates if the SET HOLD SPEED message is shown on the PFD

- A32NX_PFD_MSG_TD_REACHED
- Bool
- Indicates if the T/D REACHED message is shown on the PFD

- A32NX_PFD_LINEAR_DEVIATION_ACTIVE
- Bool
- Indicates if the linear deviation is shown on the PFD

- A32NX_PFD_TARGET_ALTITUDE
- Feet
- Indicates the current target altitude in the DES mode. This is an indicated altitude and not a pressure altitude
- This is used to compute a linear deviation

- A32NX_PFD_VERTICAL_PROFILE_LATCHED
- Boolean
- Indicates whether to show the latch symbol on the PFD with the deviation indicator

- L:A32NX_PFD_SHOW_SPEED_MARGINS
- Boolean
- Indicates whether speed margins are shown on the PFD in DES mode.

- L:A32NX_PFD_UPPER_SPEED_MARGIN
- Knots
- Indicates the speed for the upper speed margin limit in DES mode

- L:A32NX_PFD_LOWER_SPEED_MARGIN
- Knots
- Indicates the speed for the lower speed margin limit in DES mode

- A32NX_ISIS_LS_ACTIVE
- Bool
- Indicates whether LS scales are shown on the ISIS
Expand Down Expand Up @@ -1669,6 +1698,16 @@ In the variables below, {number} should be replaced with one item in the set: {
- Indicates whether the FMS should switch to APPROACH phase.
- **WARNING:** This is temporary and internal. Do not use.

- A32NX_FM_VNAV_DEBUG_POINT
- Nautical miles
- Indicates the distance from start at which to draw a debug pseudowaypoint on the ND
- **WARNING:** This is only used for testing purposes.

- A32NX_FM_VNAV_DEBUG_SPEED_BIAS
- Knots
- This is indicative of how aggressively the speed margins should be used while above the profile
- **WARNING:** This is only used for testing purposes.

## Autopilot System

- A32NX_FMA_LATERAL_MODE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ const NXSystemMessages = {
noAtisReceived: new TypeIMessage("NO ATIS REPORT RECEIVED"),
noPreviousAtis: new TypeIMessage("NO PREVIOUS ATIS STORED"),
arptTypeAlreadyInUse: new TypeIMessage("ARPT/TYPE ALREADY USED"),
cancelAtisUpdate: new TypeIMessage("CANCEL UPDATE BEFORE")
cancelAtisUpdate: new TypeIMessage("CANCEL UPDATE BEFORE"),
stepAboveMaxFl: new TypeIMessage("STEP ABOVE MAX FL"),
};

const NXFictionalMessages = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ class NXUnits {
return NXUnits.metricWeight ? value : value * 2.204625;
}

static poundsToUser(value) {
return NXUnits.metricWeight ? value / 2.204625 : value;
}

static userWeightUnit() {
return NXUnits.metricWeight ? 'KG' : 'LBS'; // EIS uses S suffix on LB
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_NavaidPage.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_NewWaypoint.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_PilotsWaypoint.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_StepAltsPage.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_VerticalRevisionPage.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_HoldAtPage.js"></script>
<script type="text/html" import-script="/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_SecFplnMain.js"></script>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,31 @@ class CDUPerformancePage {
const isSelected = Simplane.getAutoPilotAirspeedSelected();
const actModeCell = isSelected ? "SELECTED" : "MANAGED";
const costIndexCell = isFinite(mcdu.costIndex) ? mcdu.costIndex.toFixed(0) + "[color]cyan" : "[][color]cyan";

// Predictions to altitude
const vnavDriver = mcdu.guidanceController.vnavDriver;

const cruiseAltitude = mcdu.cruiseFlightLevel * 100;
const fcuAltitude = SimVar.GetSimVarValue("AUTOPILOT ALTITUDE LOCK VAR:3", "feet");
const altitudeToPredict = Math.min(cruiseAltitude, fcuAltitude);

const predToCell = CDUPerformancePage.formatAltitudeOrLevel(altitudeToPredict, mcdu.flightPlanManager.getOriginTransitionAltitude()) + "[color]cyan";

let predToDistanceCell = "---";
let predToTimeCell = "----";

let expeditePredToDistanceCell = "---";
let expeditePredToTimeCell = "----";

if (vnavDriver) {
[predToDistanceCell, predToTimeCell] = CDUPerformancePage.getTimeAndDistancePredictionsFromGeometryProfile(vnavDriver.currentNavGeometryProfile, altitudeToPredict, mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF);

if (isPhaseActive) {
const expediteProfile = vnavDriver.computeVerticalProfileForExpediteClimb();
[expeditePredToDistanceCell, expeditePredToTimeCell] = CDUPerformancePage.getTimeAndDistancePredictionsFromGeometryProfile(expediteProfile, altitudeToPredict, mcdu.flightPhaseManager.phase >= FmgcFlightPhases.TAKEOFF, true);
}
}

let managedSpeedCell = "";
if (isPhaseActive) {
if (mcdu.managedSpeedTarget === mcdu.managedSpeedClimb) {
Expand All @@ -438,7 +463,7 @@ class CDUPerformancePage {
managedSpeedCell = "{small}" + mcdu.managedSpeedTarget.toFixed(0) + "{end}";
}
} else {
managedSpeedCell = (isSelected ? "*" : "") + mcdu.managedSpeedClimb > mcdu.managedSpeedLimit ? mcdu.managedSpeedLimit.toFixed(0) : mcdu.managedSpeedClimb.toFixed(0);
managedSpeedCell = (isSelected ? "*" : "") + mcdu.managedSpeedClimb > mcdu.climbSpeedLimit ? mcdu.climbSpeedLimit.toFixed(0) : mcdu.managedSpeedClimb.toFixed(0);

mcdu.onLeftInput[3] = (value, scratchpadCallback) => {
if (mcdu.trySetPreSelectedClimbSpeed(value)) {
Expand Down Expand Up @@ -491,16 +516,16 @@ class CDUPerformancePage {
};
mcdu.setTemplate([
["CLB[color]" + titleColor],
["ACT MODE", "EFOB", timeLabel],
[actModeCell + "[color]green", "6.0[color]green", "----[color]green"],
["ACT MODE"],
[actModeCell + "[color]green"],
["\xa0CI"],
[costIndexCell + "[color]cyan"],
["\xa0MANAGED"],
["\xa0" + managedSpeedCell + "[color]green"],
[costIndexCell + "[color]cyan", predToCell, "\xa0\xa0\xa0{small}PRED TO{end}"],
["\xa0MANAGED", "DIST", timeLabel],
["\xa0" + managedSpeedCell + "[color]green", !isSelected ? predToDistanceCell : "", !isSelected ? predToTimeCell : ""],
["\xa0" + selectedSpeedTitle],
["\xa0" + selectedSpeedCell + "[color]cyan"],
[""],
["\xa0" + selectedSpeedCell, isSelected ? predToDistanceCell : "", isSelected ? predToTimeCell : ""],
[""],
isPhaseActive ? ["\xa0{small}EXPEDITE{end}[color]green", expeditePredToDistanceCell, expeditePredToTimeCell] : [""],
bottomRowLabels,
bottomRowCells
]);
Expand Down Expand Up @@ -591,7 +616,7 @@ class CDUPerformancePage {
["\xa0MANAGED"],
["\xa0" + managedSpeedCell + "[color]green"],
["\xa0" + selectedSpeedTitle],
["\xa0" + selectedSpeedCell + "[color]cyan"],
["\xa0" + selectedSpeedCell],
["", "DES CABIN RATE>"],
["", "-350FT/MIN[color]green"],
bottomRowLabels,
Expand Down Expand Up @@ -684,7 +709,7 @@ class CDUPerformancePage {
["\xa0MANAGED"],
["\xa0" + managedSpeedCell + "[color]green"],
["\xa0" + selectedSpeedTitle],
["\xa0" + selectedSpeedCell + "[color]cyan"],
["\xa0" + selectedSpeedCell],
[""],
[""],
bottomRowLabels,
Expand Down Expand Up @@ -1094,10 +1119,57 @@ class CDUPerformancePage {

static getSelectedTitleAndValue(_isPhaseActive, _isSelected, _preSel) {
if (_isPhaseActive) {
return _isSelected ? ["SELECTED", "" + Math.round(Simplane.getAutoPilotMachModeActive() ? SimVar.GetGameVarValue('FROM MACH TO KIAS', 'number', Simplane.getAutoPilotMachHoldValue()) : Simplane.getAutoPilotAirspeedHoldValue())] : ["", ""];
return _isSelected
? ["SELECTED", "" + Math.round(Simplane.getAutoPilotMachModeActive()
? SimVar.GetGameVarValue('FROM MACH TO KIAS', 'number', Simplane.getAutoPilotMachHoldValue())
: Simplane.getAutoPilotAirspeedHoldValue()) + "[color]green"]
: ["", ""];
} else {
return ["PRESEL", isFinite(_preSel) ? "" + _preSel : "*[ ]"];
return ["PRESEL", (isFinite(_preSel) ? "" + _preSel : "*[ ]") + "[color]cyan"];
}
}
static formatAltitudeOrLevel(altitudeToFormat, transitionAltitude) {
if (transitionAltitude >= 100 && altitudeToFormat > transitionAltitude) {
return `FL${(altitudeToFormat / 100).toFixed(0).toString().padStart(3,"0")}`;
}

return (10 * Math.round(altitudeToFormat / 10)).toFixed(0).toString().padStart(5,"\xa0");
}
static getTimeAndDistancePredictionsFromGeometryProfile(geometryProfile, altitudeToPredict, isFlying, printSmall = false) {
let predToDistanceCell = "---";
let predToTimeCell = "----";

if (!geometryProfile || !geometryProfile.isReadyToDisplay) {
return [predToTimeCell, predToDistanceCell];
}

const predictions = geometryProfile.computePredictionToFcuAltitude(altitudeToPredict);

if (predictions) {
if (isFinite(predictions.distanceFromStart)) {
if (printSmall) {
predToDistanceCell = "{small}" + predictions.distanceFromStart.toFixed(0) + "{end}[color]green";
} else {
predToDistanceCell = predictions.distanceFromStart.toFixed(0) + "[color]green";
}
}

if (isFinite(predictions.secondsFromPresent)) {
const utcTime = SimVar.GetGlobalVarValue("ZULU TIME", "seconds");

const predToTimeCellText = isFlying
? FMCMainDisplay.secondsToUTC(utcTime + predictions.secondsFromPresent)
: FMCMainDisplay.minutesTohhmm(predictions.secondsFromPresent);

if (printSmall) {
predToTimeCell = "{small}" + predToTimeCellText + "{end}[color]green";
} else {
predToTimeCell = predToTimeCellText + "[color]green";
}
}
}

return [predToDistanceCell, predToTimeCell];
}
}
CDUPerformancePage._timer = 0;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class CDUProgressPage {
const adirsUsesGpsAsPrimary = SimVar.GetSimVarValue("L:A32NX_ADIRS_USES_GPS_AS_PRIMARY", "Bool");
const gpsPrimaryStatus = adirsUsesGpsAsPrimary ? "{green}GPS PRIMARY{end}" : "";
let flCrz = "-----";
let vDevCell = "";
switch (mcdu.flightPhaseManager.phase) {
case FmgcFlightPhases.PREFLIGHT:
case FmgcFlightPhases.TAKEOFF: {
Expand All @@ -34,6 +35,20 @@ class CDUProgressPage {
flCrz = "FL" + mcdu.cruiseFlightLevel.toFixed(0).padStart(3, "0") + "[color]cyan";
break;
}
case FmgcFlightPhases.DESCENT: {
const vDev = mcdu.guidanceController.vnavDriver.getLinearDeviation();
let vDevFormattedNumber = "{small}-----{end}";

if (vDev && isFinite(vDev)) {
const paddedVdev = (10 * Math.round(vDev / 10)).toFixed(0).padStart(4, "\xa0");
const vDevSign = vDev > 0 ? "+" : " ";
const extraSpace = paddedVdev.length > 4 ? "" : "\xa0";

vDevFormattedNumber = "{green}" + extraSpace + vDevSign + paddedVdev + "{end}";
}

vDevCell = "{small}VDEV={end}" + vDevFormattedNumber + "{small}FT{end}";
}
}
let flightPhase;
switch (mcdu.flightPhaseManager.phase) {
Expand Down Expand Up @@ -106,7 +121,7 @@ class CDUProgressPage {
["\xa0" + "CRZ\xa0", "OPT\xa0\xa0\xa0\xa0REC MAX"],
[flCrz, flOpt + "\xa0\xa0\xa0\xa0" + "{magenta}FL" + flMax.toString() + "\xa0{end}"],
[""],
["<REPORT", ""],
["<REPORT", vDevCell],
[adirsUsesGpsAsPrimary ? "" : "\xa0POSITION UPDATE AT"],
[adirsUsesGpsAsPrimary ? "" : "{small}*{end}[\xa0\xa0\xa0\xa0][color]cyan"],
["\xa0\xa0BRG / DIST"],
Expand Down
Loading

0 comments on commit 7e33c75

Please sign in to comment.