1
0
Fork 0

Merge branch 'dev' into 3D

This commit is contained in:
Jonathan Redpath 2022-06-25 20:04:44 +01:00
commit 47749c8974
22 changed files with 982 additions and 488 deletions

View file

@ -614,6 +614,9 @@
<surveillance type="string">S</surveillance>
</icao>
<performance>
<!-- explicitly force the category to be 'E' instead of using tag heuristics
Although the A320 is a category 'C' aircraft, category 'E's profile fits better -->
<icao-category type="string">E</icao-category>
<minimum>
<takeoff-length-ft type="int">4500</takeoff-length-ft>
<landing-length-ft type="int">4500</landing-length-ft>
@ -4818,6 +4821,7 @@
<file>Aircraft/A320-family/Nasal/Panels/efis.nas</file>
</fcu>
<fmgc>
<file>Aircraft/A320-family/Nasal/FMGC/flightplan-delegates.nas</file>
<file>Aircraft/A320-family/Nasal/FMGC/flightplan-waypoints.nas</file>
<file>Aircraft/A320-family/Nasal/FMGC/flightplan.nas</file>
<file>Aircraft/A320-family/Nasal/FMGC/FMGC.nas</file>

View file

@ -170,11 +170,13 @@ var canvas_MCDU_base = {
me["Simple_L6S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C1S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C2S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C3S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C4S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C5S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C6S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R1S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R2S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R3S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R4S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R5S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R6S"].setFont("HoneywellMCDUSmall.ttf");
@ -519,9 +521,7 @@ var canvas_MCDU_base = {
me.hideAllArrows();
me.fontSizeLeft(normal, normal, normal, normal, normal, normal);
me.fontSizeCenter(normal, normal, normal, normal, normal, normal);
me.fontSizeRight(normal, normal, normal, normal, normal, normal);
me.standardFontSize();
pageSwitch[i].setBoolValue(1);
}
@ -553,6 +553,7 @@ var canvas_MCDU_base = {
me.colorLeftS("wht", "wht", "wht", "wht", "wht", "wht");
me.colorLeftArrow("wht", "wht", "wht", "wht", "wht", "wht");
me.colorCenterS("wht", "wht", "wht", "wht", "wht", "wht");
me.colorRightS("wht", "wht", "wht", "wht", "wht", "wht");
me.colorRightArrow("wht", "wht", "wht", "wht", "wht", "wht");
@ -2991,6 +2992,19 @@ var canvas_MCDU_base = {
me.colorRightS("wht", "amb", "wht", "wht", "wht", "wht");
me.colorRightArrow("wht", "wht", "wht", "wht", "wht", "wht");
me["Simple_L1S"].setText("CO RTE");
me["Simple_L2S"].setText("ALTN/CO RTE");
me["Simple_L3S"].setText("FLT NBR");
me["Simple_L5S"].setText("COST INDEX");
me["Simple_L6S"].setText("CRZ FL/TEMP");
me["Simple_R1S"].setText("FROM/TO ");
me["Simple_R2S"].setText("INIT ");
me["Simple_R5S"].setText("TROPO");
me["Simple_R6S"].setText("GND TEMP");
me["Simple_R2"].setText("REQUEST ");
me["Simple_R3"].setText("IRS INIT ");
me["Simple_R4"].setText("WIND ");
pageSwitch[i].setBoolValue(1);
}
@ -3023,13 +3037,13 @@ var canvas_MCDU_base = {
} else if (fmgc.FMGCInternal.crzSet and fmgc.FMGCInternal.crzTempSet) {
me["INITA_CruiseFLTemp"].hide();
me["Simple_L6"].setColor(BLUE);
me["Simple_L6"].setText(sprintf("%s", "FL" ~ fmgc.FMGCInternal.crzFl) ~ sprintf("/%s°", fmgc.FMGCInternal.crzTemp));
me["Simple_L6"].setText(sprintf("%s", "FL" ~ fmgc.FMGCInternal.crzFl) ~ sprintf("/%+3.0f°", fmgc.FMGCInternal.crzTemp));
} else if (fmgc.FMGCInternal.crzSet) {
me["INITA_CruiseFLTemp"].hide();
me["Simple_L6"].setColor(BLUE);
fmgc.FMGCInternal.crzTemp = 15 - (2 * fmgc.FMGCInternal.crzFl / 10);
fmgc.FMGCInternal.crzTempSet = 1;
me["Simple_L6"].setText(sprintf("%s", "FL" ~ fmgc.FMGCInternal.crzFl) ~ sprintf("/%s°", fmgc.FMGCInternal.crzTemp));
me["Simple_L6"].setText(sprintf("%s", "FL" ~ fmgc.FMGCInternal.crzFl) ~ sprintf("/%+3.0f°", fmgc.FMGCInternal.crzTemp));
} else {
me["INITA_CruiseFLTemp"].show();
me["Simple_L6"].setColor(AMBER);
@ -3072,6 +3086,7 @@ var canvas_MCDU_base = {
me["INITA_InitRequest"].hide();
}
}
if (ADIRSMCDUBTN.getValue() != 1) {
me["INITA_AlignIRS"].show();
me["Simple_R3"].setColor(AMBER);
@ -3081,41 +3096,34 @@ var canvas_MCDU_base = {
me["Simple_R3"].setColor(WHITE);
showRightArrow(me,0, 0, 1, 0, 0, 0);
}
if (fmgc.FMGCInternal.tropoSet) {
me["Simple_R5"].setFontSize(normal);
} else {
me["Simple_R5"].setFontSize(small);
}
me["Simple_R6S"].setText("GND TEMP");
if (fmgc.FMGCInternal.phase == 0 and !fmgc.FMGCInternal.gndTempSet) {
fmgc.FMGCInternal.gndTemp = 15 - (2 * getprop("/position/gear-agl-ft") / 1000);
me["Simple_R6"].setText(sprintf("%.0f°", fmgc.FMGCInternal.gndTemp));
me["Simple_R6"].setFontSize(small);
} else {
if (fmgc.FMGCInternal.phase == 0) {
if (fmgc.FMGCInternal.gndTempSet) {
me["Simple_R6"].setText(sprintf("%.0f°", fmgc.FMGCInternal.gndTemp));
me["Simple_R6"].setFontSize(normal);
} else if (fmgc.FMGCInternal.toFromSet) {
fmgc.FMGCInternal.gndTemp = 15 - (2 * (fmgc.flightPlanController.flightplans[2].departure.elevation * 3.28084) / 1000);
me["Simple_R6"].setText(sprintf("%.0f°", fmgc.FMGCInternal.gndTemp));
me["Simple_R6"].setFontSize(small);
} else {
me["Simple_R6"].setText(sprintf("%.0f°", fmgc.FMGCInternal.gndTemp));
me["Simple_R6"].setFontSize(small);
}
me["Simple_R6"].setText(sprintf("%.0f°", fmgc.FMGCInternal.gndTemp));
} else {
me["Simple_R6"].setText("---");
me["Simple_R6"].setFontSize(small);
}
me["Simple_L1S"].setText("CO RTE");
me["Simple_L2S"].setText("ALTN/CO RTE");
me["Simple_L3S"].setText("FLT NBR");
me["Simple_L5S"].setText("COST INDEX");
me["Simple_L6S"].setText("CRZ FL/TEMP");
#me["Simple_L1"].setText("NONE"); # manage before (coRoute)
me["Simple_L3"].setText(sprintf("%s", fmgc.FMGCInternal.flightNum));
me["Simple_R1S"].setText("FROM/TO ");
me["Simple_R2S"].setText("INIT ");
me["Simple_R5S"].setText("TROPO");
me["Simple_R1"].setText(sprintf("%s", fmgc.FMGCInternal.depApt ~ "/" ~ fmgc.FMGCInternal.arrApt));
me["Simple_R2"].setText("REQUEST ");
me["Simple_R3"].setText("IRS INIT ");
me["Simple_R4"].setText("WIND ");
me["Simple_R5"].setText(sprintf("%5.0f", fmgc.FMGCInternal.tropo));
} else if (page == "IRSINIT") {
if (!pageSwitch[i].getBoolValue()) {
@ -3189,9 +3197,9 @@ var canvas_MCDU_base = {
degrees = getprop("/FMGC/internal/align-ref-lat-degrees");
minutes = getprop("/FMGC/internal/align-ref-lat-minutes");
sign = getprop("/FMGC/internal/align-ref-lat-sign");
dms_lat = getprop("/FMGC/flightplan[2]/wp[0]/lat");
degrees_lat = int(dms_lat);
minutes_lat = sprintf("%.1f",abs((dms_lat - degrees_lat) * 60));
apt = airportinfo(fmgc.FMGCInternal.depApt);
degrees_lat = int(apt.lat);
minutes_lat = sprintf("%.1f",abs((apt.lat - degrees_lat) * 60));
sign_lat = degrees_lat >= 0 ? "N" : "S";
lat_same = degrees_lat == degrees and minutes_lat == minutes and sign_lat == sign;
me["Simple_L1"].setText(abs(sprintf("%.0f", degrees)) ~ "°" ~ sprintf("%.1f", minutes) ~ sign);
@ -3199,15 +3207,14 @@ var canvas_MCDU_base = {
degrees = getprop("/FMGC/internal/align-ref-long-degrees");
minutes = getprop("/FMGC/internal/align-ref-long-minutes");
sign = getprop("/FMGC/internal/align-ref-long-sign");
dms_long = getprop("/FMGC/flightplan[2]/wp[0]/lon");
degrees_long = int(dms_long);
minutes_long = sprintf("%.1f",abs((dms_long - degrees_long) * 60));
degrees_long = int(apt.lon);
minutes_long = sprintf("%.1f",abs((apt.lon - degrees_long) * 60));
sign_long = degrees_long >= 0 ? "E" : "W";
long_same = degrees_long == degrees and minutes_long == minutes and sign_long == sign;
me["Simple_R1"].setText(abs(sprintf("%.0f", degrees)) ~ "°" ~ sprintf("%.1f", minutes) ~ sign);
if (lat_same and long_same) {
me["Simple_C1"].setText(getprop("/FMGC/flightplan[2]/wp[0]/id"));
me["Simple_C1"].setText(getprop("/autopilot/route-manager/route/wp[0]/id"));
me["Simple_C1"].setColor(GREEN);
} else {
me["Simple_C1"].setText("----");
@ -3837,18 +3844,6 @@ var canvas_MCDU_base = {
me["Simple_L2"].setText(fmgc.FMGCInternal.altAirport);
}
me["Simple_L1S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_L3S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_L4S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_L5S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_L6S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_C1S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R1S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R3S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R4S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R5S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_R6S"].setFont("HoneywellMCDUSmall.ttf");
me["Simple_L1S"].setText("AT");
me["Simple_L3S"].setText("RTE RSV/%");
me["Simple_L4S"].setText("ALTN /TIME");

View file

@ -12,9 +12,9 @@ SymbolLayer.add(name, {
type: name, # Symbol type
df_controller: __self__, # controller to use by default -- this one
df_options: { # default configuration options
active_node: "/FMGC/flightplan[2]/active",
current_wp_node: "/FMGC/flightplan[2]/current-wp",
wp_num: "/FMGC/flightplan[2]/num",
active_node: "/autopilot/route-manager/active",
current_wp_node: "/autopilot/route-manager/current-wp",
wp_num: "/autopilot/route-manager/route/num",
display_inactive_rte: 0
}
});

View file

@ -79,7 +79,7 @@ var init = func {
}
var draw = func{
if (me.model.wp.hidden == 1 or me.model.name == "(DECEL)" or me.model.name == "(T/C)" or me.model.name == "(T/D)" or me.model.name == "(LIM)") {
if (me.model.wp.hidden == 1) {
me.wp_sym.hide();
me.text_wps.hide();
if (me.text_alt != nil) {

View file

@ -56,12 +56,12 @@ canvas.NDStyles["Airbus"] = {
# that the lateral flight mode is managed.
# You can easily override these options before creating the ND, example:
# canvas.NDStyles["Airbus"].options.defaults.fplan_active = "my/autpilot/f-plan/active"
fplan_active: "/FMGC/flightplan[2]/active",
fplan_active: "/autopilot/route-manager/active",
lat_ctrl: "/it-autoflight/output/lat",
managed_val: 1,
ver_ctrl: "/it-autoflight/output/vert",
spd_ctrl: "/it-autoflight/input/spd-managed",
current_wp: "/FMGC/flightplan[2]/current-wp",
current_wp: "/autopilot/route-manager/current-wp",
ap1: "/it-autoflight/output/ap1",
ap2: "/it-autoflight/output/ap2",
nav1_frq: "/instrumentation/nav[0]/frequencies/selected-mhz",
@ -72,7 +72,7 @@ canvas.NDStyles["Airbus"] = {
adf2_frq: "/instrumentation/adf[1]/frequencies/selected-khz",
dep_rwy: "/autopilot/route-manager/departure/runway",
dest_rwy: "/autopilot/route-manager/destination/runway",
wp_count: "/FMGC/flightplan[2]/num",
wp_count: "/autopilot/route-manager/route/num",
level_off_alt: "/autopilot/route-manager/vnav/level-off-alt",
athr: "/it-autoflight/output/athr",
app_mode: "/instrumentation/nd/app-mode",
@ -593,7 +593,7 @@ canvas.NDStyles["Airbus"] = {
{
name: "DECEL",
isMapStructure: 1,
update_on: ["toggle_display_mode","toggle_range"],
update_on: [ {rate_hz: 1}, "toggle_display_mode","toggle_range"],
predicate: func(nd, layer) {
var visible = nd.in_mode("toggle_display_mode", ["MAP", "PLAN"]) and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)) and getprop("/instrumentation/nd/symbols/decel/show");
layer.group.setVisible( visible );
@ -806,11 +806,10 @@ canvas.NDStyles["Airbus"] = {
id: "wpActiveId",
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/FMGC/flightplan[2]/current-leg") != nil and
getprop("/FMGC/flightplan[2]/active") and
predicate: func(nd) getprop("/autopilot/route-manager/wp[0]/id") != nil and getprop("/autopilot/route-manager/active") and
nd.in_mode("toggle_display_mode", ["MAP", "PLAN"]) and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
is_true: func(nd) {
nd.symbols.wpActiveId.setText(getprop("/FMGC/flightplan[2]/current-leg"));
nd.symbols.wpActiveId.setText(getprop("/autopilot/route-manager/wp[0]/id"));
nd.symbols.wpActiveId.show();
},
is_false: func(nd) nd.symbols.wpActiveId.hide(),
@ -820,16 +819,14 @@ canvas.NDStyles["Airbus"] = {
id: "wpActiveCrs",
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/FMGC/flightplan[2]/current-leg") != nil and
getprop("/FMGC/flightplan[2]/active") and
predicate: func(nd) getprop("/autopilot/route-manager/wp[0]/id") != nil and getprop("/autopilot/route-manager/active") and
nd.in_mode("toggle_display_mode", ["MAP", "PLAN"]) and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
is_true: func(nd) {
#var cur_wp = getprop("/autopilot/route-manager/current-wp");
var deg = nil;
if (nd.get_switch("toggle_true_north")) {
var deg = math.round(getprop("/FMGC/flightplan[2]/current-leg-course")) or 0;
var deg = math.round(getprop("/autopilot/route-manager/wp[0]/true-bearing-deg") or 0);
} else {
var deg = math.round(getprop("/FMGC/flightplan[2]/current-leg-course-mag")) or 0;
var deg = math.round(getprop("/autopilot/route-manager/wp[0]/bearing-deg") or 0);
}
if (deg != nil) {
nd.symbols.wpActiveCrs.setText(sprintf("%03.0f°", deg));
@ -845,13 +842,11 @@ canvas.NDStyles["Airbus"] = {
id: "wpActiveDist",
impl: {
init: func(nd,symbol),
predicate: func(nd) (getprop("/FMGC/flightplan[2]/current-leg-dist") != nil and
getprop("/FMGC/flightplan[2]/active") and
predicate: func(nd) (getprop("/autopilot/route-manager/wp[0]/dist") != nil and getprop("/autopilot/route-manager/active") and
nd.in_mode("toggle_display_mode", ["MAP", "PLAN"])
and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting))),
is_true: func(nd) {
var dst = getprop("/FMGC/flightplan[2]/current-leg-dist");
nd.symbols.wpActiveDist.setText(sprintf("%3.01f",dst));
nd.symbols.wpActiveDist.setText(sprintf("%3.01f", getprop("/autopilot/route-manager/wp[0]/dist")));
nd.symbols.wpActiveDist.show();
},
is_false: func(nd) nd.symbols.wpActiveDist.hide(),
@ -861,11 +856,11 @@ canvas.NDStyles["Airbus"] = {
id: "wpActiveDistLbl",
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/FMGC/flightplan[2]/current-leg-dist") != nil and getprop("/FMGC/flightplan[2]/active") and nd.in_mode("toggle_display_mode", ["MAP", "PLAN"])
and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
predicate: func(nd) getprop("/autopilot/route-manager/wp[0]/dist") != nil and getprop("/autopilot/route-manager/active") and
nd.in_mode("toggle_display_mode", ["MAP", "PLAN"]) and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
is_true: func(nd) {
nd.symbols.wpActiveDistLbl.show();
if(getprop("/FMGC/flightplan[2]/current-leg-dist") > 1000)
if(getprop("/autopilot/route-manager/wp[0]/dist") > 1000)
nd.symbols.wpActiveDistLbl.setText(" NM");
},
is_false: func(nd) nd.symbols.wpActiveDistLbl.hide(),
@ -875,8 +870,8 @@ canvas.NDStyles["Airbus"] = {
id: "eta",
impl: {
init: func(nd,symbol),
predicate: func(nd) getprop("/autopilot/route-manager/wp/eta") != nil and getprop("/FMGC/flightplan[2]/active") and nd.in_mode("toggle_display_mode", ["MAP", "PLAN"])
and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
predicate: func(nd) getprop("/autopilot/route-manager/wp/eta") != nil and getprop("/autopilot/route-manager/active")
and nd.in_mode("toggle_display_mode", ["MAP", "PLAN"]) and (nd.adirs_property.getValue() == 1 or (adirs_3.getValue() == 1 and att_switch.getValue() == nd.attitude_heading_setting)),
is_true: func(nd) {
var etaSec = getprop("/sim/time/utc/day-seconds")+
getprop("/autopilot/route-manager/wp/eta-seconds");
@ -1904,7 +1899,7 @@ canvas.NDStyles["Airbus"] = {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch("toggle_display_mode") == "MAP" and !nd.get_switch("toggle_centered")),
is_true: func(nd){
var active = getprop("/FMGC/flightplan[2]/active");
var active = getprop("/autopilot/route-manager/active");
var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
var managed_v = nd.options.defaults.managed_val;
var is_managed = (lat_ctrl == managed_v);
@ -1933,7 +1928,7 @@ canvas.NDStyles["Airbus"] = {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch("toggle_display_mode") == "MAP" and !nd.get_switch("toggle_centered")),
is_true: func(nd){
var active = getprop("/FMGC/flightplan[2]/active");
var active = getprop("/autopilot/route-manager/active");
var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
var managed_v = nd.options.defaults.managed_val;
var is_managed = (lat_ctrl == managed_v);
@ -1962,7 +1957,7 @@ canvas.NDStyles["Airbus"] = {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch("toggle_display_mode") == "MAP" and nd.get_switch("toggle_centered")),
is_true: func(nd){
var active = getprop("/FMGC/flightplan[2]/active");
var active = getprop("/autopilot/route-manager/active");
var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
var managed_v = nd.options.defaults.managed_val;
var is_managed = (lat_ctrl == managed_v);
@ -1991,7 +1986,7 @@ canvas.NDStyles["Airbus"] = {
init: func(nd,symbol),
predicate: func(nd) (nd.get_switch("toggle_display_mode") == "MAP" and nd.get_switch("toggle_centered")),
is_true: func(nd){
var active = getprop("/FMGC/flightplan[2]/active");
var active = getprop("/autopilot/route-manager/active");
var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
var managed_v = nd.options.defaults.managed_val;
var is_managed = (lat_ctrl == managed_v);
@ -2020,7 +2015,7 @@ canvas.NDStyles["Airbus"] = {
init: func(nd,symbol),
predicate: func(nd) (nd.in_mode("toggle_display_mode", ["MAP", "PLAN"])),
is_true: func(nd){
var active = getprop("/FMGC/flightplan[2]/active");
var active = getprop("/autopilot/route-manager/active");
var lat_ctrl = getprop(nd.options.defaults.lat_ctrl);
var managed_v = nd.options.defaults.managed_val;
var is_managed = (lat_ctrl == managed_v);

View file

@ -1702,7 +1702,7 @@ var canvas_pfd = {
}
notification.radioNo = fmgc.FMGCInternal.radioNo;
if (fmgc.FMGCInternal.phase < 3 or fmgc.flightPlanController.arrivalDist >= 250) {
if (fmgc.FMGCInternal.phase < 3 or fmgc.flightPlanController.arrivalDist.getValue() >= 250) {
notification.showDecisionHeight = 0;
} else {
notification.showDecisionHeight = 1;

View file

@ -294,7 +294,10 @@ var FCUController = {
HDGPush: func() {
if (me.FCUworking) {
if (fmgc.Output.fd1.getBoolValue() or fmgc.Output.fd2.getBoolValue() or fmgc.Output.ap1.getBoolValue() or fmgc.Output.ap2.getBoolValue()) {
fmgc.Input.lat.setValue(1);
var wp = fmgc.flightPlanController.flightplans[2].getWP(fmgc.flightPlanController.currentToWptIndex.getValue());
if (wp != nil and wp.wp_type != "discontinuity" and wp.wp_type != "vectors") {
fmgc.Input.lat.setValue(1);
}
}
}
},

View file

@ -14,21 +14,21 @@ var Controls = {
};
var FPLN = {
active: props.globals.getNode("/FMGC/flightplan[2]/active", 1),
active: props.globals.getNode("/autopilot/route-manager/active", 1),
activeTemp: 0,
currentCourse: 0,
currentWp: props.globals.getNode("/FMGC/flightplan[2]/current-wp", 1),
currentWpTemp: 0,
currentWP: props.globals.getNode("/autopilot/route-manager/current-wp", 1),
currentWPTemp: 0,
deltaAngle: 0,
deltaAngleRad: 0,
distCoeff: 0,
maxBank: 0,
maxBankLimit: 0,
nextCourse: 0,
R: 0,
radius: 0,
R: 0,
turnDist: 0,
wp0Dist: props.globals.getNode("/FMGC/flightplan[2]/current-leg-dist", 1),
wp0Dist: props.globals.getNode("/autopilot/route-manager/wp[0]/dist", 1),
wpFlyFrom: 0,
wpFlyTo: 0,
};
@ -367,26 +367,21 @@ var ITAF = {
slowLoop: func() {
Velocities.trueAirspeedKtTemp = Velocities.trueAirspeedKt.getValue();
FPLN.activeTemp = FPLN.active.getValue();
FPLN.currentWpTemp = FPLN.currentWp.getValue();
FPLN.currentWPTemp = FPLN.currentWP.getValue();
# If in LNAV mode and route is not longer active, switch to HDG HLD
if (Output.lat.getValue() == 1) { # Only evaulate the rest of the condition if we are in LNAV mode
if (flightPlanController.num[2].getValue() == 0 or !FPLN.active.getBoolValue()) {
if (flightPlanController.num[2].getValue() == 0 or !FPLN.activeTemp) {
me.setLatMode(3);
}
}
# Waypoint Advance Logic
if (flightPlanController.num[2].getValue() > 0 and FPLN.activeTemp == 1) {
if ((FPLN.currentWpTemp + 1) < flightPlanController.num[2].getValue()) {
Velocities.groundspeedMps = Velocities.groundspeedKt.getValue() * 0.5144444444444;
FPLN.wpFlyFrom = FPLN.currentWpTemp;
if (FPLN.wpFlyFrom < 0) {
FPLN.wpFlyFrom = 0;
}
FPLN.currentCourse = fmgc.wpCourse[2][FPLN.wpFlyFrom].getValue();
FPLN.wpFlyTo = FPLN.currentWpTemp + 1;
FPLN.nextCourse = fmgc.wpCourse[2][FPLN.wpFlyTo].getValue();
if (flightPlanController.num[2].getValue() > 0 and FPLN.activeTemp == 1 and FPLN.currentWPTemp != -1) {
if ((FPLN.currentWPTemp + 1) < flightPlanController.num[2].getValue()) {
Velocities.groundspeedMps = pts.Velocities.groundspeed.getValue() * 0.5144444444444;
FPLN.currentCourse = getprop("/autopilot/route-manager/route/wp[" ~ FPLN.currentWPTemp ~ "]/leg-bearing-true-deg");
FPLN.nextCourse = getprop("/autopilot/route-manager/route/wp[" ~ (FPLN.currentWPTemp + 1) ~ "]/leg-bearing-true-deg");
FPLN.maxBankLimit = Internal.bankLimit.getValue();
FPLN.deltaAngle = math.abs(geo.normdeg180(FPLN.currentCourse - FPLN.nextCourse));
@ -405,11 +400,17 @@ var ITAF = {
if (Gear.wow0.getBoolValue() and FPLN.turnDist < 1) {
FPLN.turnDist = 1;
}
Internal.lnavAdvanceNm.setValue(FPLN.turnDist);
if (FPLN.wp0Dist.getValue() <= FPLN.turnDist and !Gear.wow1.getBoolValue() and fmgc.flightPlanController.flightplans[2].getWP(FPLN.currentWpTemp).fly_type == "flyBy") {
# This is removed because sequencing is done by the flightplan controller
# Internal.lnavAdvanceNm.setValue(FPLN.turnDist);
# TODO - if the waypoint is the DEST waypoint, crosstrack error must be less than 0.5nm and course error less than 30 deg
# TODO - if in HDG mode, if no distance, then crosstrack error must be less than 5nm
# TODO - if in nav, no distance condition applies, but DEST course error must be less than 30 (CONFIRM)
if (abs(FPLN.deltaAngle) < 120 and FPLN.wp0Dist.getValue() <= FPLN.turnDist and !Gear.wow1.getBoolValue() and fmgc.flightPlanController.flightplans[2].getWP(FPLN.currentWPTemp).fly_type == "flyBy") {
flightPlanController.autoSequencing();
} elsif (FPLN.wp0Dist.getValue() <= 0.15) {
} elsif (FPLN.wp0Dist.getValue() <= 0.15 and !Gear.wow1.getBoolValue()) {
flightPlanController.autoSequencing();
}
}
@ -961,6 +962,12 @@ var ITAF = {
},
};
setlistener(Gear.wow1, func(val) {
if (!val.getBoolValue() and FPLN.currentWP.getValue() == 0) {
flightPlanController.autoSequencing();
}
});
setlistener("/it-autoflight/input/ap1", func() {
Input.ap1Temp = Input.ap1.getBoolValue();
if (Input.ap1Temp != Output.ap1.getBoolValue()) {

View file

@ -29,6 +29,8 @@ var mng_alt_spd = 0;
var mng_alt_mach = 0;
var altsel = 0;
var crzFl = 0;
var xtrkError = 0;
var courseDistanceDecel = 0;
var windHdg = 0;
var windSpeed = 0;
var windsDidChange = 0;
@ -444,7 +446,7 @@ var updateFuel = func {
if (FMGCInternal.toFromSet and FMGCInternal.crzSet and FMGCInternal.crzTempSet and FMGCInternal.zfwSet) {
crz = FMGCInternal.crzFl;
temp = FMGCInternal.crzTemp;
dist = flightPlanController.arrivalDist;
dist = flightPlanController.arrivalDist.getValue();
trpWind = FMGCInternal.tripWind;
wind_value = FMGCInternal.tripWindValue;
@ -458,7 +460,7 @@ var updateFuel = func {
trip_fuel = math.clamp(trip_fuel, 400, 80000);
# cruize temp correction
trip_fuel = trip_fuel + (0.033 * (temp - 15 + (2 * crz / 10)) * flightPlanController.arrivalDist);
trip_fuel = trip_fuel + (0.033 * (temp - 15 + (2 * crz / 10)) * flightPlanController.arrivalDist.getValue());
trip_time = 9.095e-02 + (dist*-3.968e-02) + (dist*dist*4.302e-04) + (dist*dist*dist*2.005e-07) + (dist*dist*dist*dist*-6.876e-11) + (dist*dist*dist*dist*dist*1.432e-14) + (dist*dist*dist*dist*dist*dist*-1.177e-18) + (crz*7.348e-01) + (dist*crz*3.310e-03) + (dist*dist*crz*-8.700e-06) + (dist*dist*dist*crz*-4.214e-10) + (dist*dist*dist*dist*crz*5.652e-14) + (dist*dist*dist*dist*dist*crz*-6.379e-18) + (crz*crz*-1.449e-02) + (dist*crz*crz*-7.508e-06) + (dist*dist*crz*crz*4.529e-08) + (dist*dist*dist*crz*crz*3.699e-13) + (dist*dist*dist*dist*crz*crz*8.466e-18) + (crz*crz*crz*1.108e-04) + (dist*crz*crz*crz*-4.126e-08) + (dist*dist*crz*crz*crz*-9.645e-11) + (dist*dist*dist*crz*crz*crz*-1.544e-16) + (crz*crz*crz*crz*-4.123e-07) + (dist*crz*crz*crz*crz*1.831e-10) + (dist*dist*crz*crz*crz*crz*7.438e-14) + (crz*crz*crz*crz*crz*7.546e-10) + (dist*crz*crz*crz*crz*crz*-1.921e-13) + (crz*crz*crz*crz*crz*crz*-5.453e-13);
trip_time = math.clamp(trip_time, 10, 480);
@ -643,12 +645,12 @@ var masterFMGC = maketimer(0.2, func {
}
} elsif (FMGCInternal.phase == 3) {
if (FMGCInternal.crzFl >= 200) {
if ((flightPlanController.arrivalDist <= 200 and altSel < 20000)) {
if ((flightPlanController.arrivalDist.getValue() <= 200 or altSel < 20000)) {
newphase = 4;
systems.PNEU.pressMode.setValue("DE");
}
} else {
if ((flightPlanController.arrivalDist <= 200 and altSel < (FMGCInternal.crzFl * 100))) { # todo - not sure about crzFl condition, investigate what happens!
if ((flightPlanController.arrivalDist.getValue() <= 200 or altSel < (FMGCInternal.crzFl * 100))) { # todo - not sure about crzFl condition, investigate what happens!
newphase = 4;
systems.PNEU.pressMode.setValue("DE");
}
@ -668,11 +670,18 @@ var masterFMGC = maketimer(0.2, func {
newphase = 2;
}
}
xtrkError = getprop("/instrumentation/gps/wp/wp[1]/course-error-nm");
if (flightPlanController.num[2].getValue() > 0 and getprop("/FMGC/flightplan[2]/active") == 1 and
flightPlanController.arrivalDist <= 15 and (Modes.PFD.FMA.rollMode == "NAV" or Modes.PFD.FMA.rollMode == "LOC" or Modes.PFD.FMA.rollMode == "LOC*") and pts.Position.gearAglFt.getValue() < 9500) { #todo decel pseudo waypoint
FMGCInternal.decel = 1;
} elsif (FMGCInternal.decel and (FMGCInternal.phase == 0 or FMGCInternal.phase == 6)) {
if (flightPlanController.decelPoint != nil) {
courseDistanceDecel = courseAndDistance(flightPlanController.decelPoint.lat, flightPlanController.decelPoint.lon);
if (flightPlanController.num[2].getValue() > 0 and fmgc.flightPlanController.active.getBoolValue() and flightPlanController.decelPoint != nil and (courseDistanceDecel[1] <= 5 and (math.abs(courseDistanceDecel[0] - pts.Orientation.heading.getValue()) >= 90 and xtrkError <= 5) or courseDistanceDecel[1] <= 0.1) and (Modes.PFD.FMA.rollMode == "NAV" or Modes.PFD.FMA.rollMode == "LOC" or Modes.PFD.FMA.rollMode == "LOC*") and pts.Position.gearAglFt.getValue() < 9500) {
FMGCInternal.decel = 1;
setprop("/instrumentation/nd/symbols/decel/show", 0);
} elsif (FMGCInternal.decel and (FMGCInternal.phase == 0 or FMGCInternal.phase == 6)) {
FMGCInternal.decel = 0;
}
} else {
FMGCInternal.decel = 0;
}

View file

@ -0,0 +1,311 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# NOTE! This copyright does *not* cover user models that use these Nasal
# services by normal function calls - this is merely considered normal use
# of the code, and does *not* fall under the heading of "derived work."
#
# Copyright (C) 2012-202 by James Turner
# route_manager.nas - FlightPlan delegate(s) corresponding to the built-
# in route-manager dialog and GPS. Intended to provide a sensible default behaviour,
# but can be disabled by an aircraft-specific FMS / GPS system.
# This delegate corresponds to functionality of the built-in route-manager dialog.
# if you disable it, the built-in route-manager dialog may not work as expected.
# Especially, this dialog is responsible for building departure, approach and
# arrival waypoints corresponding to the requested SID/STAR/approach,
# and replacing them when the inputs change (eg, user seelcted a different
# destination or STAR while enroute)
#
# You can disable the default GPS behaviour *without* touching this delegate : they are
# kept seperate since this first one is less likely to need changes
var A320RouteManagerDelegate = {
new: func(fp) {
var m = { parents: [A320RouteManagerDelegate] };
logprint(LOG_INFO, 'creating A320 Route Manager FPDelegate');
m.flightplan = fp;
return m;
},
departureChanged: func
{
logprint(LOG_INFO, 'saw departure changed');
me.flightplan.clearWPType('sid');
if (me.flightplan.departure == nil)
return;
if (me.flightplan.departure_runway == nil) {
# no runway, only an airport, use that
var wp = createWPFrom(me.flightplan.departure);
wp.wp_role = 'sid';
me.flightplan.insertWP(wp, 0);
return;
}
# first, insert the runway itself
var wp = createWPFrom(me.flightplan.departure_runway);
wp.wp_role = 'sid';
me.flightplan.insertWP(wp, 0);
if (me.flightplan.sid == nil)
return;
# and we have a SID
var sid = me.flightplan.sid;
logprint(LOG_INFO, 'routing via SID ' ~ sid.id);
var wps = sid.route(me.flightplan.departure_runway, me.flightplan.sid_trans);
var lastWP = wps[-1];
var foundIdx = -999;
for (var wptIdx = 0; wptIdx < me.flightplan.getPlanSize(); wptIdx = wptIdx + 1) {
if (me.flightplan.getWP(wptIdx).id == lastWP.id) {
foundIdx = wptIdx;
break;
}
}
if (foundIdx != -999) {
while (foundIdx > 0) {
me.flightplan.deleteWP(1);
foundIdx -= 1;
}
}
me.flightplan.insertWaypoints(wps, 1);
},
arrivalChanged: func
{
me.flightplan.clearWPType('star');
me.flightplan.clearWPType('approach');
if (me.flightplan.destination == nil)
return;
if (me.flightplan.destination_runway == nil) {
# no runway, only an airport, use that
var wp = createWPFrom(me.flightplan.destination);
wp.wp_role = 'approach';
me.flightplan.appendWP(wp);
return;
}
var initialApproachFix = nil;
if (me.flightplan.star != nil) {
logprint(LOG_INFO, 'routing via STAR ' ~ me.flightplan.star.id);
var wps = me.flightplan.star.route(me.flightplan.destination_runway, me.flightplan.star_trans);
if (wps != nil) {
me.flightplan.insertWaypoints(wps, -1);
initialApproachFix = wps[-1]; # final waypoint of STAR
}
}
if (me.flightplan.approach != nil) {
var wps = nil;
var approachIdent = me.flightplan.approach.id;
if (me.flightplan.approach_trans != nil) {
# if an approach transition was specified, let's use it explicitly
wps = me.flightplan.approach.route(me.flightplan.destination_runway, me.flightplan.approach_trans);
if (wps == nil) {
logprint(LOG_WARN, "couldn't route approach " ~ approachIdent ~ " based on specified transition:" ~ me.flightplan.approach_trans);
}
} else if (initialApproachFix != nil) {
# no explicit approach transition, let's use the IAF to guess one
wps = me.flightplan.approach.route(me.flightplan.destination_runway, initialApproachFix);
if (wps == nil) {
logprint(LOG_INFO, "couldn't route approach " ~ approachIdent ~ " based on IAF:" ~ initialApproachFix.wp_name);
}
}
# depending on the order the user selects the approach or STAR, we might get into
# a mess here. If we failed to route so far, just try a direct to the approach
if (wps == nil) {
# route direct
wps = me.flightplan.approach.route(me.flightplan.destination_runway);
}
if (wps == nil) {
logprint(LOG_WARN, 'routing via approach ' ~ approachIdent ~ ' failed entirely.');
} else {
me.flightplan.insertWaypoints(wps, -1);
}
} else {
# no approach, just use the runway waypoint
var wp = createWPFrom(me.flightplan.destination_runway);
wp.wp_role = 'approach';
me.flightplan.appendWP(wp);
}
},
cleared: func
{
logprint(LOG_INFO, "saw active flightplan cleared, deactivating");
# see http://https://code.google.com/p/flightgear-bugs/issues/detail?id=885
fgcommand("activate-flightplan", props.Node.new({"activate": 0}));
},
endOfFlightPlan: func
{
logprint(LOG_INFO, "end of flight-plan, deactivating");
fgcommand("activate-flightplan", props.Node.new({"activate": 0}));
}
};
var GPSPath = "/instrumentation/gps";
# this delegate corresponds to the default behaviour of the built-in GPS.
# depending on the real GPS/FMS you are modelling, you probably need to
# replace this with your own.
#
# To do that, just set /autopilot/route-manager/disable-fms to true, which
# will block creation of this delegate.
#
# Of course you are then responsible for many basic FMS functions, such as
# route sequencing and activation
#
var A320GPSDelegate = {
new: func(fp) {
var m = { parents: [A320GPSDelegate], flightplan:fp, landingCheck:nil };
logprint(LOG_INFO, 'creating A320 GPS FPDelegate');
# tell the GPS C++ code we will do sequencing ourselves, so it can disable
# its legacy logic for this
setprop(GPSPath ~ '/config/delegate-sequencing', 1);
# disable turn anticipation
setprop(GPSPath ~ '/config/enable-fly-by', 0);
# flyOver maximum distance
setprop(GPSPath ~ '/config/over-flight-arm-distance', 5);
fp.followLegTrackToFix = 1;
fp.aircraftCategory = 'C';
m._modeProp = props.globals.getNode(GPSPath ~ '/mode');
return m;
},
_landingCheckTimeout: func
{
if (pts.Gear.wow[0].getValue() and pts.Velocities.groundspeed.getValue() < 25) {
logprint(LOG_INFO, 'GPS saw speed < 25kts on destination runway, end of route.');
me.landingCheck.stop();
# record touch-down time?
me.flightplan.finish();
}
},
_captureCurrentCourse: func
{
setprop(GPSPath ~ "/selected-course-deg", getprop(GPSPath ~ "/desired-course-deg"));
},
_selectOBSMode: func
{
setprop(GPSPath ~ "/command", "obs");
},
waypointsChanged: func
{
},
activated: func
{
if (!me.flightplan.active)
return;
logprint(LOG_INFO,'flightplan activated, default GPS to LEG mode');
setprop(GPSPath ~ "/command", "leg");
},
deactivated: func
{
if (me._modeProp.getValue() == 'leg') {
logprint(LOG_INFO, 'flightplan deactivated, default GPS to OBS mode');
me._captureCurrentCourse();
me._selectOBSMode();
}
},
endOfFlightPlan: func
{
if (me._modeProp.getValue() == 'leg') {
logprint(LOG_INFO, 'end of flight-plan, switching GPS to OBS mode');
me._captureCurrentCourse();
me._selectOBSMode();
}
},
cleared: func
{
if (!me.flightplan.active)
return;
if (me._modeProp.getValue() == 'leg') {
logprint(LOG_INFO, 'flight-plan cleared, switching GPS to OBS mode');
me._captureCurrentCourse();
me._selectOBSMode();
}
},
sequence: func
{
if (!me.flightplan.active)
return;
if (me._modeProp.getValue() == 'leg') {
if (me.flightplan.current + 1 >= me.flightplan.numWaypoints()) {
logprint(LOG_INFO, "default GPS sequencing, finishing flightplan");
me.flightplan.finish();
} elsif (me.flightplan.nextWP().wp_type != 'discontinuity' and me.flightplan.nextWP().wp_type != 'vectors') {
logprint(LOG_INFO, "default GPS sequencing to next WP");
me.flightplan.current = me.flightplan.current + 1;
} else {
logprint(LOG_INFO, "default GPS sequencing to next WP (special)");
fmgc.Input.lat.setValue(3);
if (me.flightplan.nextWP().wp_type == 'vectors') {
me.flightplan.current = me.flightplan.current + 2;
}
}
} else {
# OBS, do nothing
}
},
currentWaypointChanged: func
{
if (!me.flightplan.active)
return;
if (me.landingCheck != nil) {
me.landingCheck.stop();
me.landingCheck = nil; # delete timer
}
var active = me.flightplan.currentWP();
if (active == nil) return;
var activeRunway = active.runway();
# this check is needed to avoid problems with circular routes; when
# activating the FP we end up here, and without this check, immediately
# detect that we've 'landed' and finish the FP again.
if (!pts.Gear.wow[0].getValue() and
(activeRunway != nil) and (me.flightplan.destination_runway != nil) and
(activeRunway.id == me.flightplan.destination_runway.id))
{
me.landingCheck = maketimer(2.0, me, A320GPSDelegate._landingCheckTimeout);
me.landingCheck.start();
}
}
};
registerFlightPlanDelegate(A320GPSDelegate.new);
registerFlightPlanDelegate(A320RouteManagerDelegate.new);

View file

@ -17,50 +17,41 @@ var DEBUG_DISCONT = 0;
var magHDG = props.globals.getNode("/orientation/heading-magnetic-deg", 1);
var trueHDG = props.globals.getNode("/orientation/heading-deg", 1);
# Props.initNode
var wpID = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/id", "", "STRING")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/id", "", "STRING")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/id", "", "STRING")]];
var wpLat = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/lat", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/lat", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/lat", 0, "DOUBLE")]];
var wpLon = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/lon", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/lon", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/lon", 0, "DOUBLE")]];
var wpCourse = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/course", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/course", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/course", 0, "DOUBLE")]];
var wpDistance = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/distance", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/distance", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/distance", 0, "DOUBLE")]];
var wpCoursePrev = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/course-from-prev", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/course-from-prev", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/course-from-prev", 0, "DOUBLE")]];
var wpDistancePrev = [[props.globals.initNode("/FMGC/flightplan[0]/wp[0]/distance-from-prev", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[1]/wp[0]/distance-from-prev", 0, "DOUBLE")], [props.globals.initNode("/FMGC/flightplan[2]/wp[0]/distance-from-prev", 0, "DOUBLE")]];
var flightPlanController = {
flightplans: [createFlightplan(), createFlightplan(), createFlightplan(), nil],
temporaryFlag: [0, 0],
# These flags are only for the main flgiht-plan
active: props.globals.initNode("/FMGC/flightplan[2]/active", 0, "BOOL"),
changed: props.globals.initNode("/FMGC/flightplan[2]/changed", 0, "BOOL"),
active: props.globals.initNode("/autopilot/route-manager/active", 0, "BOOL"),
changed: props.globals.initNode("/autopilot/route-manager/flightplan-changed", 0, "BOOL"),
currentToWpt: nil, # container for the current TO waypoint ghost
currentToWptIndex: props.globals.initNode("/FMGC/flightplan[2]/current-wp", 0, "INT"),
currentToWptIndex: props.globals.initNode("/autopilot/route-manager/current-wp", 1, "INT"),
currentToWptIndexTemp: 0,
currentToWptID: props.globals.initNode("/FMGC/flightplan[2]/current-leg", "", "STRING"),
courseToWpt: props.globals.initNode("/FMGC/flightplan[2]/current-leg-course", 0, "DOUBLE"),
courseMagToWpt: props.globals.initNode("/FMGC/flightplan[2]/current-leg-course-mag", 0, "DOUBLE"),
distToWpt: props.globals.initNode("/FMGC/flightplan[2]/current-leg-dist", 0, "DOUBLE"),
currentToWptIndexTemp2: 0,
currentToWptID: props.globals.initNode("/autopilot/route-manager/wp[0]/id", "", "STRING"),
courseToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/true-bearing-deg", 0, "DOUBLE"),
courseMagToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/bearing-deg", 0, "DOUBLE"),
distToWpt: props.globals.initNode("/autopilot/route-manager/wp[0]/dist", 0, "DOUBLE"),
wptType: nil,
wptTypeNoAdvanceDelete: 0,
distanceToDest: [0, 0, 0],
num: [props.globals.initNode("/FMGC/flightplan[0]/num", 0, "INT"), props.globals.initNode("/FMGC/flightplan[1]/num", 0, "INT"), props.globals.initNode("/FMGC/flightplan[2]/num", 0, "INT")],
# Temporary flightplan will use flightplan[0] and flightplan[1]
num: [props.globals.initNode("/FMGC/flightplan[0]/num", 0, "INT"), props.globals.initNode("/FMGC/flightplan[1]/num", 0, "INT"), props.globals.initNode("/autopilot/route-manager/route/num", 0, "INT")],
arrivalIndex: [0, 0, 0],
arrivalDist: 0,
_arrivalDist: 0,
arrivalDist: props.globals.getNode("/autopilot/route-manager/distance-remaining-nm"),
fromWptTime: nil,
fromWptAlt: nil,
_timeTemp: nil,
_altTemp: nil,
decelPoint: nil,
init: func() {
me.resetFlightplan(2);
me.insertPPOS(2);
me.addDiscontinuity(1, 2, 1);
me.currentToWptIndex.setValue(0);
me.flightPlanChanged(2);
me.flightplans[2].activate();
},
reset: func() {
@ -69,6 +60,9 @@ var flightPlanController = {
me.resetFlightplan(0);
me.resetFlightplan(1);
me.resetFlightplan(2);
me.decelPoint = nil;
setprop("/instrumentation/nd/symbols/decel/show", 0);
me.flightplans[2].activate();
},
resetFlightplan: func(n) {
@ -80,8 +74,11 @@ var flightPlanController = {
mcdu.isNoSid[n] = 0;
mcdu.isNoStar[n] = 0;
mcdu.isNoVia[n] = 0;
me.arrivalIndex[n] = 0; # reset arrival index calculations
},
oldCurrentWp: 0,
lastSequencedCurrentWP: 0,
createTemporaryFlightPlan: func(n) {
me.resetFlightplan(n);
me.flightplans[n] = me.flightplans[2].clone();
@ -96,11 +93,16 @@ var flightPlanController = {
canvas_mcdu.myAirways[n].updateTmpy();
}
fmgc.windController.createTemporaryWinds(n);
me.oldCurrentWp = FPLN.currentWP.getValue();
me.flightPlanChanged(n);
},
loadFlightPlan: func(path) {
call(func {me.flightplans[3] = createFlightplan(path);}, nil, var err = []);
call(func {
me.flightplans[3] = createFlightplan(path);
}, nil, var err = []);
if (size(err) or me.flightplans[3] == nil) {
print(err[0]);
print("Load failed.");
@ -108,12 +110,12 @@ var flightPlanController = {
me.destroyTemporaryFlightPlan(3, 1);
},
destroyTemporaryFlightPlan: func(n, a) { # a = 1 activate, a = 0 erase
destroyTemporaryFlightPlan: func(n, a) { # a = 1 activate, a = 0 erase, s = 0 don't call flightplan changed
if (a == 1) {
flightPlanTimer.stop();
me.resetFlightplan(2);
me.flightplans[2] = me.flightplans[n].clone();
me.flightplans[2].activate();
if (n != 3) {
if (mcdu.isNoSid[n] == 1) {
mcdu.isNoSid[2] = 1;
@ -145,17 +147,30 @@ var flightPlanController = {
mcdu.isNoTransArr[2] = 0;
}
}
me.flightPlanChanged(2);
flightPlanTimer.start();
}
if (n == 3) { return; }
me.resetFlightplan(n);
if (n == 3) {
me.flightPlanChanged(n);
return;
}
me.temporaryFlag[n] = 0;
me.flightPlanChanged(2);
me.resetFlightplan(n);
if (canvas_mcdu.myDirTo[n] != nil) {
canvas_mcdu.myDirTo[n].updateTmpy();
}
if (me.DirToIndex != nil) {
me.currentToWptIndex.setValue(me.DirToIndex);
me.DirToIndex = nil;
}
fmgc.windController.destroyTemporaryWinds(n, a);
if (FPLN.currentWP.getValue() != me.oldCurrentWp) {
FPLN.currentWP.setValue(me.oldCurrentWp);
}
me.flightPlanChanged(n);
},
@ -164,9 +179,8 @@ var flightPlanController = {
me.flightplans[plan].departure = airportinfo(dep);
me.flightplans[plan].destination = airportinfo(arr);
if (plan == 2) {
me.destroyTemporaryFlightPlan(0, 0);
me.destroyTemporaryFlightPlan(1, 0);
me.currentToWptIndex.setValue(0);
if (me.temporaryFlag[0]) { me.destroyTemporaryFlightPlan(0, 0); }
if (me.temporaryFlag[1]) { me.destroyTemporaryFlightPlan(1, 0); }
me.arrivalIndex = [0, 0, 0]; # reset arrival index calculations
}
me.addDiscontinuity(1, plan);
@ -177,7 +191,6 @@ var flightPlanController = {
if (canvas_mcdu.myArrival[1] != nil) { canvas_mcdu.myArrival[1].reset(); }
if (canvas_mcdu.myDeparture[0] != nil) { canvas_mcdu.myDeparture[0].reset(); }
if (canvas_mcdu.myDeparture[1] != nil) { canvas_mcdu.myDeparture[1].reset(); }
#todo if plan = 2, kill any tmpy flightplan
me.flightPlanChanged(plan);
},
@ -201,45 +214,31 @@ var flightPlanController = {
},
autoSequencing: func() {
me.calculateTimeAltitudeOnSequence();
if (!me.active.getBoolValue()) { return; }
if (pts.Sim.pause.getBoolValue()) { return; }
# todo setlistener on sim/time/warp to recompute predictions
me.calculateTimeAltitudeOnSequence();
# Advancing logic
me.currentToWptIndexTemp = me.currentToWptIndex.getValue();
if (me.currentToWptIndexTemp < 1) {
me.currentToWptIndex.setValue(1);
} else if (me.num[2].getValue() > 2) {
if (me.currentToWptIndexTemp == 2) { # Clean up after a no-sequence waypoint
me.currentToWptIndex.setValue(1); # MUST be set first
# TODO: Add support for deleting multiple waypoints at once, this will do for now
if (me.temporaryFlag[0] == 1 and wpID[0][0] == wpID[2][0]) {
me.deleteWP(0, 0);
}
if (me.temporaryFlag[1] == 1 and wpID[1][0] == wpID[2][0]) {
me.deleteWP(0, 1);
}
me.deleteWP(0, 2, 0, 1);
if (me.temporaryFlag[0] == 1 and wpID[0][0] == wpID[2][0]) {
me.deleteWP(0, 0);
}
if (me.temporaryFlag[1] == 1 and wpID[1][0] == wpID[2][0]) {
me.deleteWP(0, 1);
}
me.deleteWP(0, 2, 0, 1);
} else {
me.wptType = me.flightplans[2].getWP(me.currentToWptIndexTemp).wp_type;
me.wptTypeNoAdvanceDelete = me.wptType == "radialIntercept" or me.wptType == "vectors" or me.wptType == "dmeIntercept" or me.wptType == "hdgToAlt";
if (me.wptTypeNoAdvanceDelete) {
me.currentToWptIndex.setValue(2);
} else {
if (me.temporaryFlag[0] == 1 and wpID[0][0] == wpID[2][0]) {
me.deleteWP(0, 0);
# TODO - after sequencing discontinuity, FPLN should show PPOS then DISCONTINUITY
# Clearing that discontinuity is not allowed, you must exit using DIRTO, or else using NAV ARM and overfly
# TODO - triple click - confirm, is it only with DES disengage, or also with the NAV loss?
# TODO - I think that it only goes to VS when in DES mode
if (me.flightplans[2].getWP(me.currentToWptIndexTemp + 1).wp_type == "discontinuity" or me.flightplans[2].getWP(me.currentToWptIndexTemp + 1).wp_type == "vectors") {
fmgc.Input.lat.setValue(3);
me.currentToWptIndex.setValue(me.currentToWptIndexTemp + 2);
me.lastSequencedCurrentWP = me.currentToWptIndexTemp + 2;
} else {
me.currentToWptIndex.setValue(me.currentToWptIndexTemp + 1);
me.lastSequencedCurrentWP = me.currentToWptIndexTemp + 1;
if (me.num[2].getValue() > 2 and me.currentToWptIndexTemp >= 1) {
for (var i = 0; i <= 2; i += 1) {
if (i == 2 or me.temporaryFlag[i]) {
me.flightplans[i].getWP(me.currentToWptIndexTemp - 1).hidden = 1;
}
if (me.temporaryFlag[1] == 1 and wpID[1][0] == wpID[2][0]) {
me.deleteWP(0, 1);
}
me.deleteWP(0, 2, 0, 1);
}
}
}
@ -262,15 +261,17 @@ var flightPlanController = {
# addDiscontinuity - insert discontinuity at passed index
# args: index, plan
# index: index to add at
# plan: plan to add to
# index: index to add at
# plan: plan to add to
# Check if a discontinuity already exists either immediately before or at that index
# If it does, don't add another one
# Optional flag DEBUG_DISCONT to disable discontinuities totally
addDiscontinuity: func(index, plan, force = 0) {
if (DEBUG_DISCONT) { return; }
if (force) {
me.flightplans[plan].insertWP(createDiscontinuity(), index);
return;
}
if (me.flightplans[plan].getWP(index) != nil) { # index is not nil
@ -288,18 +289,15 @@ var flightPlanController = {
me.flightplans[plan].insertWP(createDiscontinuity(), index);
}
} else { # both are nil??
print("Possible error in discontinuities!");
me.flightplans[plan].insertWP(createDiscontinuity(), index);
debug.dump("Error in discontinuities; won't try to add one");
}
},
# insertTP - insert PPOS waypoint denoted "T-P" at specified index
# args: n, index
# n: flightplan to which the PPOS waypoint will be inserted
# index: optional argument, defaults to 1, index which the waypoint will be at.
# Default to one, as direct to will insert TP, then create leg to DIRTO waypoint, then delete waypoint[0]
insertTP: func(n, index = 1) {
# n: flightplan to which the PPOS waypoint will be inserted
# index: index which the waypoint will be at.
insertTP: func(n, index) {
me.flightplans[n].insertWP(createWP(geo.aircraft_position(), "T-P"), index);
fmgc.windController.insertWind(n, index, 0, "T-P");
},
@ -309,13 +307,14 @@ var flightPlanController = {
fmgc.windController.insertWind(n, index, 0, "PPOS");
},
# childWPBearingDistance - return waypoint at bearing and distance from specified waypoint ghost
# args: wpt, bearing, dist, name, typeStr
# wpt: waypoint ghost
# bearing: bearing of waypoint to be created from specified waypoint
# distance: distance of waypoint to be created from specified waypoint, nautical miles
# name: name of waypoint to be created
# typeStr: optional argument to be passed to createWP, must be one of "sid", "star" "approach" "missed" or "pseudo"
# wpt: waypoint ghost
# bearing: bearing of waypoint to be created from specified waypoint
# distance: distance of waypoint to be created from specified waypoint, nautical miles
# name: name of waypoint to be created
# typeStr: optional argument to be passed to createWP, must be one of "sid", "star" "approach" "missed" or "pseudo"
childWPBearingDistance: func(wpt, bearing, dist) {
var coordinates = greatCircleMove(wpt.lat, wpt.lon, num(bearing), num(dist));
@ -335,7 +334,9 @@ var flightPlanController = {
}
# fudge the altitude since we cannot create a hdgtoAlt from nasal. Assume 600 feet per mile - 2.5 miles
me.flightplans[n].insertWP(createWP(me.childWPBearingDistance(wptStore, me.flightplans[n].departure_runway.heading, 2.5), "1500", "sid"), 1);
me.flightplans[n].insertWP(createWP(me.childWPBearingDistance(wptStore, me.flightplans[n].departure_runway.heading, 2.5 + (me.flightplans[n].departure_runway.length * M2NM)), "1500", "sid"), 1);
me.flightplans[n].getWP(1).fly_type = "flyOver";
me.flightplans[n].getWP(1).setAltitude(1500, "at");
fmgc.windController.insertWind(n, 1, 0, "1500");
}
me.flightPlanChanged(n);
@ -357,6 +358,7 @@ var flightPlanController = {
hdg = hdg - 360;
}
me.flightplans[n].insertWP(createWP(me.childWPBearingDistance(wptStore, hdg, 5), "CF", "star"), me.arrivalIndex[n]);
me.flightplans[n].getWP(me.arrivalIndex[n]).fly_type = "flyOver";
fmgc.windController.insertWind(n, me.arrivalIndex[n], 0, "CF");
}
me.flightPlanChanged(n);
@ -364,8 +366,8 @@ var flightPlanController = {
# directTo - create leg direct from present position to a specified waypoint
# args: waypointGhost, plan
# waypointGost: waypoint ghost of the waypoint
# plan: plan on which the direct to leg will be created
# waypointGost: waypoint ghost of the waypoint
# plan: plan on which the direct to leg will be created
# We first insert a PPOS waypoint at index 1
# We check if the flightplan already contains the waypoint passed to the function
# If it exists, we delete intermediate waypoints
@ -373,49 +375,50 @@ var flightPlanController = {
# In either case, we delete the current FROM waypoint, index 0, and call flightPlanChanged to recalculate
# We attempt to get the distance from the aircraft current position to the chosen waypoint and update mcdu with it
DirToIndex: nil,
directTo: func(waypointGhost, plan) {
if (me.flightplans[plan].indexOfWP(waypointGhost) == -1) {
me.insertTP(plan, 1);
me.insertTP(plan, me.currentToWptIndex.getValue());
# use createWP here as createWPFrom doesn't accept waypoints
# createWPFrom worked before... but be sure!
me.flightplans[plan].insertWP(createWP(waypointGhost, waypointGhost.id), 2);
fmgc.windController.insertWind(plan, 2, 0, waypointGhost.id);
me.addDiscontinuity(3, plan);
me.flightplans[plan].insertWP(createWP(waypointGhost, waypointGhost.id), me.currentToWptIndex.getValue() + 1);
fmgc.windController.insertWind(plan, me.currentToWptIndex.getValue() + 1, 0, waypointGhost.id);
me.addDiscontinuity(me.currentToWptIndex.getValue() + 2, plan);
me.DirToIndex = me.currentToWptIndex.getValue() + 1;
} else {
# we want to delete the intermediate waypoints up to but not including the waypoint. Leave index 0, we delete it later.
# example - waypoint dirto is index 5, we want to delete indexes 1 -> 4. 5 - 1 = 4.
# so four individual deletions. Delete index 1 four times.
var indexWP = me.flightplans[plan].indexOfWP(waypointGhost);
me.insertTP(plan, indexWP);
me.deleteTillIndex(waypointGhost, me.currentToWptIndex.getValue(), plan, 1);
var timesToDelete = me.flightplans[plan].indexOfWP(waypointGhost);
while (timesToDelete > 1) {
me.deleteWP(1, plan, 1);
timesToDelete -= 1;
}
# Add TP afterwards, this is essential
me.insertTP(plan, 1);
indexWP = me.flightplans[plan].indexOfWP(waypointGhost);
me.hideTillIndex(indexWP - 2, plan);
me.DirToIndex = indexWP;
}
var curAircraftPosDirTo = geo.aircraft_position();
canvas_mcdu.myDirTo[plan].updateDist(me.flightplans[plan].getWP(2).courseAndDistanceFrom(curAircraftPosDirTo)[1]);
me.deleteWP(0, plan);
me.flightPlanChanged(plan);
canvas_mcdu.myDirTo[plan].updateDist(me.flightplans[plan].getWP(me.currentToWptIndex.getValue() + 1).courseAndDistanceFrom(curAircraftPosDirTo)[1]);
},
deleteWP: func(index, n, a = 0, s = 0) { # a = 1, means adding a waypoint via deleting intermediate. s = 1, means autosequencing
var wp = wpID[n][index].getValue();
if (((s == 0 and left(wp, 4) != FMGCInternal.depApt and left(wp, 4) != FMGCInternal.arrApt) or (s == 1)) and me.flightplans[n].getPlanSize() > 2) {
if (me.flightplans[n].getWP(index).id != "DISCONTINUITY" and a == 0) { # if it is a discont, don't make a new one
deleteWP: func(index, n, a = 0) { # a = 1, means adding a waypoint via deleting intermediate
var wp = me.flightplans[n].getWP(index);
if ((left(wp.wp_name, 4) != FMGCInternal.depApt and left(wp.wp_name, 4) != FMGCInternal.arrApt) and me.flightplans[n].getPlanSize() > 2) {
if (wp.id != "DISCONTINUITY" and a == 0) { # if it is a discont, don't make a new one
me.flightplans[n].deleteWP(index);
fmgc.windController.deleteWind(n, index);
if (me.flightplans[n].getWP(index) != nil and s == 0) {
if (me.flightplans[n].getWP(index) != nil) { # This refers to the next one after the one we deleted
if (me.flightplans[n].getWP(index).id != "DISCONTINUITY") { # else, if the next one isn't a discont, add one
me.addDiscontinuity(index, n);
}
}
} else {
me.flightplans[n].deleteWP(index);
fmgc.windController.deleteWind(n, index);
if (wp.id == "DISCONTINUITY" and index > 0 and (me.flightplans[n].getWP(index - 1).id == "PPOS" or find("VECTORS", me.flightplans[n].getWP(index - 1).id) != -1)) {
return 1;
} else {
me.flightplans[n].deleteWP(index);
fmgc.windController.deleteWind(n, index);
}
}
me.flightPlanChanged(n);
canvas_nd.A3XXRouteDriver.triggerSignal("fp-removed");
return 2;
@ -427,8 +430,8 @@ var flightPlanController = {
# deleteTillIndex - helper that deletes waypoints up to a passed waypoint already in flightplan
# uses a while loop to delete a certain number of waypoints between passed index and
# index of waypoint alredy in flightplan
deleteTillIndex: func(wpGhost, index, plan) {
var numToDel = me.flightplans[plan].indexOfWP(wpGhost) - index;
deleteTillIndex: func(wpGhost, index, plan, offset = 0) {
var numToDel = me.flightplans[plan].indexOfWP(wpGhost) - index - offset;
while (numToDel > 0) {
me.deleteWP(index, plan, 1);
numToDel -= 1;
@ -436,6 +439,15 @@ var flightPlanController = {
return 2;
},
hideTillIndex: func(index, plan) {
var numToDel = index;
while (numToDel >= 0) {
me.flightplans[plan].getWP(index - numToDel).hidden = 1;
numToDel -= 1;
}
return 2;
},
# createDuplicateNames - helper to spawn DUPLICATENAMES page
# args: ghostContainer, index, flag, plan
# ghostContainer: vector of fgPositioned ghosts
@ -473,7 +485,7 @@ var flightPlanController = {
}
var indexPresent = me.flightplans[plan].indexOfWP(airport[indexToInsert]);
if (me.flightplans[plan].indexOfWP(airport[indexToInsert]) == -1) {
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
me.flightplans[plan].insertWP(createWPFrom(airport[indexToInsert]), index);
fmgc.windController.insertWind(plan, index, 0, text);
me.addDiscontinuity(index + 1, plan);
@ -507,7 +519,7 @@ var flightPlanController = {
}
var indexPresent = me.flightplans[plan].indexOfWP(fix[indexToInsert]);
if (me.flightplans[plan].indexOfWP(fix[indexToInsert]) == -1) {
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
me.flightplans[plan].insertWP(createWPFrom(fix[indexToInsert]), index);
fmgc.windController.insertWind(plan, index, 1, text);
me.addDiscontinuity(index + 1, plan);
@ -541,7 +553,7 @@ var flightPlanController = {
}
var indexPresent = me.flightplans[plan].indexOfWP(navaid[indexToInsert]);
if (me.flightplans[plan].indexOfWP(navaid[indexToInsert]) == -1) {
if (indexPresent == -1 or indexPresent > me.arrivalIndex[plan]) {
me.flightplans[plan].insertWP(createWPFrom(navaid[indexToInsert]), index);
fmgc.windController.insertWind(plan, index, 1, text);
me.addDiscontinuity(index + 1, plan);
@ -561,7 +573,8 @@ var flightPlanController = {
return 1;
}
if (me.flightplans[plan].indexOfWP(wpGhost) == -1) {
var indexCurr = me.flightplans[plan].indexOfWP(wpGhost);
if (indexCurr == -1 or indexCurr > me.arrivalIndex[plan]) {
# use createWP here as createWPFrom doesn't accept waypoints
me.flightplans[plan].insertWP(createWP(wpGhost, wpGhost.wp_name), index);
fmgc.windController.insertWind(plan, index, 1, wpGhost.wp_name);
@ -602,13 +615,13 @@ var flightPlanController = {
# getWPforPBD - parse scratchpad text to find waypoint ghost for PBD
# args: text, index, plan
# text: scratchpad text
# index: index at which waypoint will be inserted
# plan: plan to which waypoint will be inserted
# text: scratchpad text
# index: index at which waypoint will be inserted
# plan: plan to which waypoint will be inserted
# return:
# 0: not in database
# 1: notAllowed
# 2: o.k.
# 0: not in database
# 1: notAllowed
# 2: o.k.
getWPforPBD: func(text, index, plan, override = 0, overrideIndex = -1) {
if (index == 0) {
@ -669,7 +682,6 @@ var flightPlanController = {
getNavCount: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
#print(me.flightplans[plan].getWP(wpt).wp_type);
if (me.flightplans[plan].getWP(wpt).wp_type == "navaid") {
count += 1;
}
@ -680,7 +692,6 @@ var flightPlanController = {
getDepartureCount: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
#print(me.flightplans[plan].getWP(wpt).wp_role);
if (me.flightplans[plan].getWP(wpt).wp_role == "sid") {
count += 1;
}
@ -698,12 +709,64 @@ var flightPlanController = {
return count;
},
getPlanSizeNoDiscont: func(plan) {
var count = 0;
for (var wpt = 0; wpt < me.flightplans[plan].getPlanSize(); wpt += 1) {
if (me.flightplans[plan].getWP(wpt).wp_name != "DISCONTINUITY") {
count += 1;
}
}
return count;
},
calculateDecelPoint: func() {
if (me.getPlanSizeNoDiscont(2) <= 1 or fmgc.FMGCInternal.decel) {
setprop("/instrumentation/nd/symbols/decel/show", 0);
return;
}
me.indexDecel = 0;
for (var wpt = 0; wpt < me.flightplans[2].getPlanSize(); wpt += 1) {
if (me.flightplans[2].getWP(wpt).wp_role == "approach") {
me.indexDecel = wpt;
break;
}
if (wpt == me.flightplans[2].getPlanSize()) {
me.indexDecel = me.arrivalIndex - 2;
break;
}
}
me.dist = me.flightplans[2].getWP(me.indexDecel).leg_distance - 7;
if (me.dist < 0) {
me.dist = 0.1;
}
me.decelPoint = me.flightplans[2].pathGeod(me.indexDecel - 1, me.dist);
setprop("/instrumentation/nd/symbols/decel/latitude-deg", me.decelPoint.lat);
setprop("/instrumentation/nd/symbols/decel/longitude-deg", me.decelPoint.lon);
setprop("/instrumentation/nd/symbols/decel/show", 1);
me.indexTemp = me.indexDecel;
me.distTemp = 7;
if (me.flightplans[2].getWP(me.indexTemp).leg_distance < 7) {
while (me.distTemp > 0 and me.indexTemp > 0) {
me.distTemp -= me.flightplans[2].getWP(me.indexTemp).leg_distance;
me.indexTemp -= 1;
}
me.indexTemp += 1;
}
setprop("/instrumentation/nd/symbols/decel/index", me.indexTemp);
},
# insertPlaceBearingDistance - insert PBD waypoint at specified index,
# at some specified bearing, distance from a specified location
# args: wp, index, plan
# wpt: waypoint ghost
# index: index to insert at in plan
# plan: plan to insert to
# wpt: waypoint ghost
# index: index to insert at in plan
# plan: plan to insert to
insertPlaceBearingDistance: func(wp, bearing, distance, index, plan) {
var waypoint = pilotWaypoint.new(me.childWPBearingDistance(wp, bearing, distance), "PBD");
@ -724,8 +787,18 @@ var flightPlanController = {
return 3;
}
if (!fmgc.flightPlanController.temporaryFlag[plan]) {
if (index == me.currentToWptIndex.getValue()) {
return 1;
# TODO - implement the PPOS - DISCONT feature
# me.insertPPOS(thePlan, index - 1);
# me.addDiscontinuity(index - 1, thePlan, 1);
}
if (!me.temporaryFlag[plan]) {
if (text == "CLR" and me.flightplans[2].getWP(index).wp_name == "DISCONTINUITY") {
if (me.flightplans[2].getPlanSize() == 3 and me.flightplans[2].departure_runway == nil and me.flightplans[2].destination_runway == nil and index == 1) {
return 1;
}
var thePlan = 2;
} else {
fmgc.flightPlanController.createTemporaryFlightPlan(plan);
@ -735,6 +808,7 @@ var flightPlanController = {
var thePlan = plan;
}
# check waypoints database here
var wpFromDB = WaypointDatabase.getWP(text);
if (wpFromDB != nil) {
@ -761,20 +835,9 @@ var flightPlanController = {
},
flightPlanChanged: func(n) {
sizeWP = size(wpID[n]);
for (var counter = sizeWP; counter < me.flightplans[n].getPlanSize(); counter += 1) { # create new properties if they are required
append(wpID[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/text", "", "STRING"));
append(wpLat[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/lat", 0, "DOUBLE"));
append(wpLon[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/lon", 0, "DOUBLE"));
append(wpCourse[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/course", 0, "DOUBLE"));
append(wpDistance[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/distance", 0, "DOUBLE"));
append(wpCoursePrev[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/course-from-prev", 0, "DOUBLE"));
append(wpDistancePrev[n], props.globals.initNode("/FMGC/flightplan[" ~ n ~ "]/wp[" ~ counter ~ "]/distance-from-prev", 0, "DOUBLE"));
}
me.updatePlans();
me.updatePlans(1);
fmgc.windController.updatePlans();
# push update to fuel
if (fmgc.FMGCInternal.blockConfirmed) {
fmgc.FMGCInternal.fuelCalculating = 0;
@ -788,47 +851,36 @@ var flightPlanController = {
canvas_nd.A3XXRouteDriver.triggerSignal("fp-added");
},
updatePlans: func() {
me.updateCurrentWaypoint();
me._arrivalDist = 0;
# runDecel - used to ensure that only flightplanchanged will update the decel point
updatePlans: func(runDecel = 0) {
if (fmgc.FMGCInternal.toFromSet and me.flightplans[2].departure != nil and me.flightplans[2].destination != nil) { # check if flightplan exists
if (!me.active.getBoolValue()) {
if (me.currentToWptIndex.getValue() < 1) {
var errs = [];
call(func {
if (me.flightplans[2].getWP(1).id != "DISCONTINUITY") {
me.currentToWptIndex.setValue(1);
}
}, nil, nil, nil, errs);
if (size(errs) != 0) { debug.printerror(errs); }
}
me.active.setValue(1);
}
} elsif (me.active.getBoolValue()) {
me.active.setValue(0);
}
if (me.active.getBoolValue() and me.currentToWptIndex.getValue() == -1) {
me.currentToWptIndex.setValue(me.lastSequencedCurrentWP);
}
for (var n = 0; n <= 2; n += 1) {
for (var wpt = 0; wpt < me.flightplans[n].getPlanSize(); wpt += 1) { # Iterate through the waypoints and update their data
var curAircraftPos = geo.aircraft_position(); # don't want to get this corrupted so make sure it is a local variable
var waypointHashStore = me.flightplans[n].getWP(wpt);
courseDistanceFrom = waypointHashStore.courseAndDistanceFrom(curAircraftPos);
wpID[n][wpt].setValue(waypointHashStore.wp_name);
wpLat[n][wpt].setValue(waypointHashStore.wp_lat);
wpLon[n][wpt].setValue(waypointHashStore.wp_lon);
wpCourse[n][wpt].setValue(waypointHashStore.courseAndDistanceFrom(curAircraftPos)[0]);
wpDistance[n][wpt].setValue(waypointHashStore.courseAndDistanceFrom(curAircraftPos)[1]);
if (wpt == 1) {
if (me.flightplans[n].getWP(wpt).wp_name != "DISCONTINUITY" and me.flightplans[n].getWP(wpt).wp_type != "vectors" and me.flightplans[n].getWP(wpt).wp_type != "hdgToAlt" and wpt <= me.arrivalIndex[n]) {
# print("Adding " ~ courseDistanceFrom[1] ~ " miles for waypoint " ~ me.flightplans[n].getWP(wpt).wp_name);
me._arrivalDist += courseDistanceFrom[1]; # distance to next waypoint, therafter to end of flightplan
}
}
if (wpt > 0) {
wpCoursePrev[n][wpt].setValue(me.flightplans[n].getWP(wpt).leg_bearing);
wpDistancePrev[n][wpt].setValue(me.flightplans[n].getWP(wpt).leg_distance);
#if (wpt > 1) {
# if (me.flightplans[n].getWP(wpt - 1).wp_name != "DISCONTINUITY" and me.flightplans[n].getWP(wpt).wp_name != "DISCONTINUITY" and me.flightplans[n].getWP(wpt - 1).wp_type != "vectors" and me.flightplans[n].getWP(wpt - 1).wp_type != "hdgToAlt" and me.flightplans[n].getWP(wpt).wp_type != "vectors" and me.flightplans[n].getWP(wpt).wp_type != "hdgToAlt" and wpt <= me.arrivalIndex[n]) {
# me._arrivalDist += courseDistanceFromPrev[1];
# }
#}
} else {
# use PPOS for the first waypoint
wpCoursePrev[n][wpt].setValue(courseDistanceFrom[0]);
wpDistancePrev[n][wpt].setValue(courseDistanceFrom[1]);
}
if (left(wpID[n][wpt].getValue(), 4) == fmgc.FMGCInternal.arrApt and wpt != 0) {
if (left(waypointHashStore.wp_name, 4) == fmgc.FMGCInternal.arrApt and wpt != 0) {
if (me.arrivalIndex[n] != wpt) {
me.arrivalIndex[n] = wpt;
if (canvas_mcdu.myFpln[0] != nil) {
canvas_mcdu.myFpln[0].destInfo();
}
@ -837,74 +889,13 @@ var flightPlanController = {
}
}
}
}
}
}
if (runDecel) {
me.calculateDecelPoint();
}
if (me.flightplans[2].getWP(me.arrivalIndex[2]) == nil or me.flightplans[2].getWP(1) == nil) {
me.arrivalDist = 9999;
#print(me.arrivalIndex[2]);
} else {
me.arrivalDist = me.flightplans[2].getWP(me.arrivalIndex[2]).distance_along_route - me.flightplans[2].getWP(1).leg_distance + me._arrivalDist;
}
me.updateMCDUDriver(n);
},
updateCurrentWaypoint: func() {
for (var india = 0; india <= 2; india += 1) {
if (FMGCInternal.toFromSet and me.flightplans[india].departure != nil and me.flightplans[india].destination != nil) { # check if flightplan exists
var curAircraftPos = geo.aircraft_position(); # don't want to get this corrupted so make sure it is a local variable
if (india == 2) { # main plan
if (!me.active.getBoolValue()) {
me.active.setValue(1);
}
if (me.currentToWptIndex.getValue() > me.flightplans[india].getPlanSize()) {
me.currentToWptIndex.setValue(me.flightplans[india].getPlanSize());
}
me.currentToWpt = me.flightplans[india].getWP(me.currentToWptIndex.getValue());
if (me.currentToWptID.getValue() != me.currentToWpt.wp_name) {
me.currentToWptID.setValue(me.currentToWpt.wp_name);
}
me.courseToWpt.setValue(me.currentToWpt.courseAndDistanceFrom(curAircraftPos)[0]);
me.distToWpt.setValue(me.currentToWpt.courseAndDistanceFrom(curAircraftPos)[1]);
magTrueError = magHDG.getValue() - trueHDG.getValue();
storeCourse = me.courseToWpt.getValue() + magTrueError;
if (storeCourse >= 360) {
storeCourse -= 360;
} elsif (storeCourse < 0) {
storeCourse += 360;
}
me.courseMagToWpt.setValue(storeCourse);
}
if (me.num[india].getValue() != me.flightplans[india].getPlanSize()) {
me.num[india].setValue(me.flightplans[india].getPlanSize());
}
} else {
if (india == 2) {
if (me.active.getBoolValue()) {
me.active.setValue(0);
}
if (me.currentToWptID.getValue() != "") {
me.currentToWptID.setValue("");
}
}
if (me.num[india].getValue() != 0) {
me.num[india].setValue(0);
}
}
}
},
updateMCDUDriver: func() {
for (var i = 0; i <= 1; i += 1) {
if (canvas_mcdu.myFpln[i] != nil) {
canvas_mcdu.myFpln[i].updatePlan();
@ -916,4 +907,4 @@ var flightPlanController = {
},
};
var flightPlanTimer = maketimer(0.1, flightPlanController, flightPlanController.updatePlans);
var flightPlanTimer = maketimer(0.1, flightPlanController, flightPlanController.updatePlans);

View file

@ -5,11 +5,13 @@ print("------------------------------------------------");
print("Copyright (c) 2016-2022 Josh Davidson (Octal450)");
print("------------------------------------------------");
setprop("/autopilot/route-manager/disable-route-manager", 1);
setprop("/autopilot/route-manager/disable-fms", 1);
# Disable specific menubar items
setprop("/sim/menubar/default/menu[0]/item[0]/enabled", 0);
setprop("/sim/menubar/default/menu[2]/item[0]/enabled", 0);
setprop("/sim/menubar/default/menu[2]/item[2]/enabled", 0);
setprop("/sim/menubar/default/menu[3]/enabled", 0);
setprop("/sim/menubar/default/menu[5]/item[9]/enabled", 0);
setprop("/sim/menubar/default/menu[5]/item[10]/enabled", 0);
setprop("/sim/menubar/default/menu[5]/item[11]/enabled", 0);

View file

@ -1,3 +1,6 @@
# A3XX MCDU Direct To Page
# Copyright (c) 2022 Jonathan Redpath (legoboyvdlp)
var dirToFlag = 0;
var dirTo = {
@ -77,16 +80,14 @@ var dirTo = {
canvas_mcdu.myFpln[me.computer] = fplnPage.new(2, me.computer);
}
var x = 0;
var dirToLeftIndex = 0;
me.vector = [];
for (var i = 1 + (me.scroll); i < size(canvas_mcdu.myFpln[me.computer].planList) - 2; i = i + 1) {
if (canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "DISCONTINUITY" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "VECTORS" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "T-P" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_type == "hdgToAlt") { continue; }
if (canvas_mcdu.myFpln[me.computer].planList[i].index > fmgc.flightPlanController.arrivalIndex[2]) {
continue;
}
if (canvas_mcdu.myFpln[me.computer].planList[i].wp == "PSEUDO" or canvas_mcdu.myFpln[me.computer].planList[i].wp == "STATIC" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "DISCONTINUITY" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "VECTORS" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_name == "T-P" or canvas_mcdu.myFpln[me.computer].planList[i].wp.wp_type == "hdgToAlt") { continue; }
if (canvas_mcdu.myFpln[me.computer].planList[i].index > fmgc.flightPlanController.arrivalIndex[2]) { continue; }
append(me.vector, canvas_mcdu.myFpln[me.computer].planList[i].wp);
x += 1;
if (x == 4) { break; }
dirToLeftIndex += 1;
if (dirToLeftIndex == 4) { break; }
}
if (size(me.vector) > 0) {

View file

@ -1,3 +1,22 @@
# A3XX FMGC Flightplan Page
# Copyright (c) 2022 Josh Davidson (Octal450) and Jonathan Redpath (legoboyvdlp)
# Local vars
var decelIndex = 0;
var decelShow = 0;
var decelOffset = 0;
var destName = nil;
var getSubTextFunc = func(meRef) {
var subText = nil;
call(func {
subText = me.wp.wp_owner.id;
}, nil, meRef, nil,
var errs = []
);
return nil;
}
var fplnItem = {
new: func(wp, index, plan, computer, colour = "grn") {
var fI = {parents:[fplnItem]};
@ -19,10 +38,14 @@ var fplnItem = {
if (wptName[0] == "VECTORS") {
return ["MANUAL", me.getSubText(), me.colour];
} else {
if (size(wptName) == 2) {
return[wptName[0] ~ wptName[1 ~ (me.wp.fly_type == "flyOver" ? "@" : "")], me.getSubText(), me.colour];
if (me.wp.fly_type == "Hold") {
return ["HOLD " ~ (me.wp.hold_is_left_handed ? "L" : "R"), me.getSubText(), me.colour];
} else {
return [me.wp.wp_name ~ (me.wp.fly_type == "flyOver" ? "@" : ""), me.getSubText(), me.colour];
if (size(wptName) == 2) {
return[wptName[0] ~ wptName[1 ~ (me.wp.fly_type == "flyOver" ? "@" : "")], me.getSubText(), me.colour];
} else {
return [me.wp.wp_name ~ (me.wp.fly_type == "flyOver" ? "@" : ""), me.getSubText(), me.colour];
}
}
}
} else {
@ -33,7 +56,11 @@ var fplnItem = {
}
},
getSubText: func() {
return nil;
if (me.wp.wp_parent_name != nil) {
return " " ~ me.wp.wp_parent_name;
} else {
return nil;
}
},
updateCenterText: func() {
if (me.wp != nil) {
@ -47,9 +74,9 @@ var fplnItem = {
}
if (me.index == fmgc.flightPlanController.currentToWptIndex.getValue()) {
me.assembledStr[1] = "BRG" ~ me.getBrg() ~ " ";
me.assembledStr[1] = "BRG" ~ me.getBrg() ~ "° ";
} elsif (me.index == (fmgc.flightPlanController.currentToWptIndex.getValue() + 1) or me.index == (fmgc.flightPlanController.arrivalIndex[me.plan] + 1)) {
me.assembledStr[1] = "TRK" ~ me.getTrack() ~ " ";
me.assembledStr[1] = "TRK" ~ me.getTrack() ~ "° ";
} else {
me.assembledStr[1] = nil;
}
@ -67,7 +94,6 @@ var fplnItem = {
if (me.wp.wp_name != "DISCONTINUITY") {
me.spd = me.getSpd();
me.alt = me.getAlt();
me.dist = me.getDist();
if (me.colour != "yel") { # not temporary flightplan
me._colour = "wht";
#if (me.spd[1] != "wht" or me.alt[1] != "wht") {
@ -84,7 +110,7 @@ var fplnItem = {
} else { # temporary flightplan
me._colour = "yel";
}
return [me.spd[0] ~ "/" ~ me.alt[0], " " ~ me.dist ~ "NM ", me._colour];
return [me.spd[0] ~ "/" ~ me.alt[0], me.getDist() ~ "NM ", me._colour];
} else {
return [nil, nil, "ack"];
}
@ -93,17 +119,19 @@ var fplnItem = {
}
},
getBrg: func() {
me.brg = fmgc.wpCourse[me.plan][me.index].getValue() - magvar();
if (me.brg < 0) { me.brg += 360; }
if (me.brg > 360) { me.brg -= 360; }
var wp = fmgc.flightPlanController.flightplans[me.plan].getWP(me.index);
if (wp.wp_type == "vectors") {
me.brg = pts.Orientation.heading.getValue();
} else {
var courseDistanceFrom = courseAndDistance(wp);
me.brg = courseDistanceFrom[0] - magvar();
if (me.brg < 0) { me.brg += 360; }
if (me.brg > 360) { me.brg -= 360; }
}
return sprintf("%03.0f", math.round(me.brg));
},
getTrack: func() {
if (me.index > (size(fmgc.wpCoursePrev[me.plan]) - 1)) {
me.trk = me.wp.leg_bearing - magvar(me.wp.lat, me.wp.lon);
} else {
me.trk = fmgc.wpCoursePrev[me.plan][me.index].getValue() - magvar(me.wp.lat, me.wp.lon);
}
me.trk = me.wp.leg_bearing - magvar(me.wp.lat, me.wp.lon);
if (me.trk < 0) { me.trk += 360; }
if (me.trk > 360) { me.trk -= 360; }
return sprintf("%03.0f", math.round(me.trk));
@ -112,7 +140,7 @@ var fplnItem = {
if (me.index == 0 and left(me.wp.wp_name, 4) == fmgc.FMGCInternal.depApt and fmgc.FMGCInternal.v1set) {
return [sprintf("%3.0f", math.round(fmgc.FMGCInternal.v1)), "grn"]; # why "mag"? I think "grn"
} elsif (me.wp.speed_cstr != nil and me.wp.speed_cstr > 0) {
var tcol = (me.wp.speed_cstr_type == "computed" or me.wp.speed_cstr_type == "computed_mach") ? "grn" : "mag"; # TODO - check if only computed
var tcol = (me.wp.speed_cstr_type == "computed" or me.wp.speed_cstr_type == "computed_mach") ? "grn" : "mag";
return [sprintf("%3.0f", me.wp.speed_cstr), tcol];
} else {
return ["---", "wht"];
@ -124,7 +152,7 @@ var fplnItem = {
} elsif (me.index == (fmgc.flightPlanController.currentToWptIndex.getValue() - 1) and fmgc.flightPlanController.fromWptAlt != nil) {
return [" " ~ fmgc.flightPlanController.fromWptAlt, "mag"];
} elsif (me.wp.alt_cstr != nil and me.wp.alt_cstr > 0) {
var tcol = (me.wp.alt_cstr_type == "computed" or me.wp.alt_cstr_type == "computed_mach") ? "grn" : "mag"; # TODO - check if only computed
var tcol = (me.wp.alt_cstr_type == "computed" or me.wp.alt_cstr_type == "computed_mach") ? "grn" : "mag";
var cstrAlt = "";
if (me.wp.alt_cstr > fmgc.FMGCInternal.transAlt) {
@ -141,13 +169,19 @@ var fplnItem = {
}
},
getDist: func() {
if (me.index > size(fmgc.wpDistancePrev[me.plan]) - 1) {
return math.round(me.wp.leg_distance);
decelIndex = getprop("/instrumentation/nd/symbols/decel/index");
decelShow = getprop("/instrumentation/nd/symbols/decel/show");
var prevwp = fmgc.flightPlanController.flightplans[me.plan].getWP(me.index -1);
if (me.index == fmgc.flightPlanController.currentToWptIndex.getValue()) {
return sprintf("%3.0f", math.round(courseAndDistance(me.wp)[1]));;
} else {
if (me.index == fmgc.flightPlanController.currentToWptIndex.getValue()) {
return math.round(fmgc.wpDistance[me.plan][me.index].getValue());
if (me.plan == 2 and decelShow and me.index == decelIndex and fmgc.flightPlanController.decelPoint != nil) {
return sprintf("%3.0f", courseAndDistance(fmgc.flightPlanController.decelPoint, me.wp)[1]);
} else if (prevwp != nil and (prevwp.wp_name != "DISCONTINUITY" or find(prevwp.wp_name, "VECTORS"))) {
return sprintf("%3.0f", math.round(me.wp.leg_distance));
} else {
return math.round(fmgc.wpDistancePrev[me.plan][me.index].getValue());
return " --";
}
}
},
@ -160,7 +194,7 @@ var fplnItem = {
if (me.wp.wp_name == "DISCONTINUITY") {
canvas_mcdu.myLatRev[me.computer] = latRev.new(4, me.wp, me.index, me.computer);
} elsif (fmgc.flightPlanController.temporaryFlag[me.computer]) {
if (me.wp.wp_name == "PPOS" or me.index == (fmgc.flightPlanController.currentToWptIndex.getValue() - 1)) {
if (me.wp.wp_name == "PPOS") {
canvas_mcdu.myLatRev[me.computer] = latRev.new(2, me.wp, me.index, me.computer);
} elsif (me.index == fmgc.flightPlanController.arrivalIndex[me.computer]) {
canvas_mcdu.myLatRev[me.computer] = latRev.new(1, me.wp, me.index, me.computer);
@ -170,7 +204,7 @@ var fplnItem = {
canvas_mcdu.myLatRev[me.computer] = latRev.new(3, me.wp, me.index, me.computer);
}
} else {
if (me.wp.wp_name == "PPOS" or me.index == (fmgc.flightPlanController.currentToWptIndex.getValue() - 1)) {
if (me.wp.wp_name == "PPOS") {
canvas_mcdu.myLatRev[me.computer] = latRev.new(2, me.wp, me.index, me.computer);
} elsif (me.index == fmgc.flightPlanController.arrivalIndex[2]) {
canvas_mcdu.myLatRev[me.computer] = latRev.new(1, me.wp, me.index, me.computer);
@ -271,6 +305,7 @@ var staticText = {
var sT = {parents:[staticText]};
sT.computer = computer;
sT.text = text;
sT.wp = "STATIC";
return sT;
},
updateLeftText: func() {
@ -291,21 +326,34 @@ var staticText = {
};
var pseudoItem = {
new: func(computer, text) {
new: func(computer, text, colour) {
var pI = {parents:[pseudoItem]};
pI.computer = computer;
pI.text = text;
pI.colour = colour;
pI.wp = "PSEUDO";
return pI;
},
updateLeftText: func() {
return [me.text, nil, me.colour];
},
updateCenterText: func() {
return ["----", nil, "wht"];
return ["---- ", nil, "wht"];
},
getDist: func() {
decelIndex = getprop("/instrumentation/nd/symbols/decel/index");
decelShow = getprop("/instrumentation/nd/symbols/decel/show");
if (decelShow) {
var prevWP = fmgc.flightPlanController.flightplans[2].getWP(decelIndex - 1);
if (prevWP != nil and prevWP.wp_name != "DISCONTINUITY") {
return sprintf("%3.0f", courseAndDistance(prevWP, fmgc.flightPlanController.decelPoint)[1]);
} else {
return " --";
}
}
},
updateRightText: func() {
return ["---/------", " --NM ", "wht"];
return ["---/------", me.getDist() ~ "NM ", "wht"];
},
pushButtonLeft: func() {
mcdu_message(me.computer, "NOT ALLOWED");
@ -384,31 +432,56 @@ var fplnPage = { # this one is only created once, and then updated - remember th
} else {
colour = "grn";
}
for (var i = 0; i < me.plan.getPlanSize(); i += 1) {
decelIndex = getprop("/instrumentation/nd/symbols/decel/index");
decelShow = getprop("/instrumentation/nd/symbols/decel/show");
var startingIndex = fmgc.flightPlanController.currentToWptIndex.getValue() == -1 ? 0 : fmgc.flightPlanController.currentToWptIndex.getValue() - 1;
# Situation where currentIndex is equal to 0
startingIndex = (startingIndex == -1 ? 0 : startingIndex);
for (var i = startingIndex; i < me.plan.getPlanSize(); i += 1) {
if (!me.temporaryFlagFpln and decelShow) {
if (i == decelIndex) {
append(me.planList, pseudoItem.new(me.computer, me.getText("decel"), colour));
}
}
if (!me.temporaryFlagFpln and i > fmgc.flightPlanController.arrivalIndex[me.planIndex] and fmgc.FMGCInternal.phase != 6) {
append(me.planList, fplnItem.new(me.plan.getWP(i), i, me.planIndex, me.computer, "blu"));
} else {
append(me.planList, fplnItem.new(me.plan.getWP(i), i, me.planIndex, me.computer, colour));
if (i == fmgc.flightPlanController.currentToWptIndex.getValue() and !me.temporaryFlagFpln) {
append(me.planList, fplnItem.new(me.plan.getWP(i), i, me.planIndex, me.computer, "wht"));
} else {
append(me.planList, fplnItem.new(me.plan.getWP(i), i, me.planIndex, me.computer, colour));
}
}
}
append(me.planList, staticText.new(me.computer, me.getText("fplnEnd")));
if (!fmgc.FMGCInternal.altAirportSet) {
append(me.planList, staticText.new(me.computer, me.getText("noAltnFpln")));
} else {
var altnApt = findAirportsByICAO(fmgc.FMGCInternal.altAirport)[0];
append(me.planList, fplnItem.new({
alt_cstr: nil,
alt_cstr_type: nil,
fly_type: "flyBy",
lat: altnApt.lat,
leg_bearing: courseAndDistance(findAirportsByICAO(fmgc.FMGCInternal.arrApt)[0], altnApt)[0],
leg_distance: courseAndDistance(findAirportsByICAO(fmgc.FMGCInternal.arrApt)[0], altnApt)[1],
lon: altnApt.lon,
speed_cstr: nil,
speed_cstr_type: nil,
wp_name: fmgc.FMGCInternal.altAirport,
}, i, me.planIndex, me.computer, "blu"));
append(me.planList, staticText.new(me.computer, me.getText("altnFplnEnd")));
var altnApt = findAirportsByICAO(fmgc.FMGCInternal.altAirport);
if (size(altnApt) > 0) {
append(me.planList, fplnItem.new({
alt_cstr: nil,
alt_cstr_type: nil,
fly_type: "flyBy",
lat: altnApt[0].lat,
leg_bearing: courseAndDistance(findAirportsByICAO(fmgc.FMGCInternal.arrApt)[0], altnApt[0])[0],
leg_distance: courseAndDistance(findAirportsByICAO(fmgc.FMGCInternal.arrApt)[0], altnApt[0])[1],
lon: altnApt[0].lon,
speed_cstr: nil,
speed_cstr_type: nil,
wp_name: fmgc.FMGCInternal.altAirport,
wp_parent_name: nil,
}, i, me.planIndex, me.computer, "blu"));
append(me.planList, staticText.new(me.computer, me.getText("altnFplnEnd")));
} else {
append(me.planList, staticText.new(me.computer, me.getText("noAltnFpln")));
}
}
me.basePage();
@ -468,7 +541,7 @@ var fplnPage = { # this one is only created once, and then updated - remember th
},
destInfo: func() {
if (me.plan.getWP(fmgc.flightPlanController.arrivalIndex[me.planIndex]) != nil) {
var destName = split("-", me.plan.getWP(fmgc.flightPlanController.arrivalIndex[me.planIndex]).wp_name);
destName = split("-", me.plan.getWP(fmgc.flightPlanController.arrivalIndex[me.planIndex]).wp_name);
if (size(destName) == 2) {
me.L6 = [destName[0] ~ destName[1], " DEST", "wht"];
} else {
@ -478,8 +551,8 @@ var fplnPage = { # this one is only created once, and then updated - remember th
me.L6 = ["----", " DEST", "wht"];
}
me.C6 = ["---- ", "TIME ", "wht"];
if (fmgc.flightPlanController.arrivalDist != nil) {
me.R6 = [sprintf("%4.0f", int(fmgc.flightPlanController.arrivalDist)) ~ " --.-", "DIST EFOB", "wht"];
if (fmgc.flightPlanController.arrivalDist.getValue() != nil) {
me.R6 = [sprintf("%4.0f", int(fmgc.flightPlanController.arrivalDist.getValue())) ~ " --.-", "DIST EFOB", "wht"];
} else {
me.R6 = ["---- --.-", "DIST EFOB", "wht"];
}
@ -487,15 +560,26 @@ var fplnPage = { # this one is only created once, and then updated - remember th
update: func() {
#me.basePage();
},
planIndexFunc: func() {
decelIndex = getprop("/instrumentation/nd/symbols/decel/index");
decelShow = getprop("/instrumentation/nd/symbols/decel/show");
if (me.scroll < me.plan.getPlanSize()) {
decelOffset = 0;
if (decelShow) {
if (me.scroll > decelIndex) {
decelOffset = 1;
}
}
setprop("/instrumentation/efis[" ~ me.computer ~ "]/inputs/plan-wpt-index", (fmgc.flightPlanController.currentToWptIndex.getValue() - 1 + me.scroll - decelOffset));
}
},
scrollUp: func() {
if (size(me.planList) > 1) {
me.scroll += 1;
if (me.scroll > size(me.planList) - 3) {
me.scroll = 0;
}
if (me.scroll < me.plan.getPlanSize()) {
setprop("/instrumentation/efis[" ~ me.computer ~ "]/inputs/plan-wpt-index", me.scroll);
}
me.planIndexFunc();
} else {
me.scroll = 0;
setprop("/instrumentation/efis[" ~ me.computer ~ "]/inputs/plan-wpt-index", -1);
@ -507,9 +591,7 @@ var fplnPage = { # this one is only created once, and then updated - remember th
if (me.scroll < 0) {
me.scroll = size(me.planList) - 3;
}
if (me.scroll < me.plan.getPlanSize()) {
setprop("/instrumentation/efis[" ~ me.computer ~ "]/inputs/plan-wpt-index", me.scroll);
}
me.planIndexFunc();
} else {
me.scroll = 0;
setprop("/instrumentation/efis[" ~ me.computer ~ "]/inputs/plan-wpt-index", -1);
@ -535,17 +617,9 @@ var fplnPage = { # this one is only created once, and then updated - remember th
setprop("MCDU[" ~ me.computer ~ "]/page", "LATREV");
}
} else {
if ((index - 1 + me.scroll) < size(me.planList) and !mcdu_scratchpad.scratchpads[me.computer].showTypeIMsg and !mcdu_scratchpad.scratchpads[me.computer].showTypeIIMsg) {
if ((index - 1 + me.scroll) < size(me.planList) and me.outputList[index - 1].wp != "STATIC" and me.outputList[index - 1].wp != "PSEUDO" and !mcdu_scratchpad.scratchpads[me.computer].showTypeIMsg and !mcdu_scratchpad.scratchpads[me.computer].showTypeIIMsg) {
if (size(mcdu_scratchpad.scratchpads[me.computer].scratchpad) > 0) {
# Use outputList.index to correct the index the call goes to after sequencing
if (mcdu_scratchpad.scratchpads[me.computer].scratchpad == "CLR") {
if (me.outputList[index - 1].wp.wp_name == "(DECEL)") {
mcdu_message(me.computer, "NOT ALLOWED");
return;
}
}
var returny = fmgc.flightPlanController.scratchpad(mcdu_scratchpad.scratchpads[me.computer].scratchpad, me.outputList[index - 1].index, me.computer);
if (returny == 3) {
mcdu_message(me.computer, "DIR TO IN PROGRESS");
@ -595,8 +669,9 @@ var decimalToShortString = func(dms, type) {
var degrees = split(".", sprintf(dms))[0];
if (type == "lat") {
var sign = degrees >= 0 ? "N" : "S";
return sprintf("%02d", abs(degrees)) ~ sign;
} else {
var sign = degrees >= 0 ? "E" : "W";
return sprintf("%03d", abs(degrees)) ~ sign;
}
return abs(degrees) ~ sign;
}

View file

@ -39,38 +39,50 @@ var holdPage = {
_setupPageWithData: func() {
me.title = ["HOLD", " AT ", me.waypoint.wp_name];
me.titleColour = "wht";
me.arrowsMatrix = [[0, 0, 0, 0, 0, 1], [1, 1, 0, 0, 0, 0]];
me.arrowsMatrix = [[0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0]];
me.arrowsColour = [["ack", "ack", "ack", "ack", "ack", "wht"], ["blu", "blu", "ack", "ack", "ack", "ack"]];
if (me.waypoint.fly_type == "Hold") {
me.makeTmpy();
me.L1 = [sprintf("%03.0f°", me.waypoint.hold_inbound_radial), "INB CRS", "blu"];
if (me.waypoint.hold_is_left_handed) {
me.L2 = ["L", " TURN", "blu"];
} else {
me.L2 = ["R", " TURN", "blu"];
}
if (me.waypoint.hold_is_distance) {
me.L3 = [" -.-/" ~ me.waypoint.hold_time_or_distance, "TIME/DIST", "blu"];
} else {
me.L3 = [sprintf("%3.1f", (me.waypoint.hold_time_or_distance / 60)) ~ "/----", "TIME/DIST", "blu"];
}
me.R1 = ["COMPUTED ", nil, "blu"];
me.R2 = ["DATABASE ", nil, "yel"];
me.R1 = ["COMPUTED ", nil, "wht"];
me.R2 = ["DATABASE ", nil, "blu"];
me.arrowsColour[1][0] = "wht";
me.arrowsColour[1][1] = "blu";
me.arrowsMatrix[1][0] = 1;
me.arrowsMatrix[1][1] = 0;
} else {
me.L1 = ["100°", "INB CRS", "blu"];
me.L2 = ["R", " TURN", "blu"];
# waypoint is a leg, figure out how to handle it
return;
me.waypoint.hold_count = 999;
me.waypoint.hold_is_left_handed = 0;
me.waypoint.hold_is_distance = 0;
me.waypoint.hold_inbound_radial = me.waypoint.leg_bearing;
if (pts.Instrumentation.Altimeter.indicatedFt.getValue() >= 14000) {
me.L3 = ["1.5/----", "TIME/DIST", "blu"];
me.waypoint.hold_time_or_distance = 90;
} else {
me.L3 = ["1.0/----", "TIME/DIST", "blu"];
me.waypoint.hold_time_or_distance = 60;
}
me.R1 = ["COMPUTED ", nil, "blu"];
me.R2 = ["DATABASE ", nil, "blu"];
me.R1 = ["COMPUTED ", nil, "yel"];
me.R2 = ["DATABASE ", nil, "wht"];
me.arrowsColour[1][0] = "yel";
me.arrowsColour[1][1] = "wht";
me.arrowsMatrix[1][0] = 0;
me.arrowsMatrix[1][1] = 1;
}
me.L6 = [" RETURN", nil, "wht"];
me.L1 = [sprintf("%03.0f°", me.waypoint.hold_inbound_radial), "INB CRS", "blu"];
if (me.waypoint.hold_is_left_handed) {
me.L2 = ["L", " TURN", "blu"];
} else {
me.L2 = ["R", " TURN", "blu"];
}
if (me.waypoint.hold_is_distance) {
me.L3 = [" -.-/" ~ me.waypoint.hold_time_or_distance, "TIME/DIST", "blu"];
} else {
me.L3 = [sprintf("%3.1f", (me.waypoint.hold_time_or_distance / 60)) ~ "/----", "TIME/DIST", "blu"];
}
me.C4 = ["LAST EXIT", nil, "wht"];
me.C5 = ["---- ---.-", "UTC FUEL", "wht"];
canvas_mcdu.pageSwitch[me.computer].setBoolValue(0);
@ -82,23 +94,67 @@ var holdPage = {
},
updateTmpy: func() {
if (fmgc.flightPlanController.temporaryFlag[me.computer]) {
me.L1[2] = "yel";
me.L2[2] = "yel";
me.L3[2] = "yel";
me.L6 = [" F-PLN", " TMPY", "yel"];
me.R6 = ["INSERT ", " TMPY", "yel"];
me.arrowsColour[0][5] = "yel";
me.titleColour = "yel";
canvas_mcdu.pageSwitch[me.computer].setBoolValue(0);
} else {
me.L1[2] = "blu";
me.L2[2] = "blu";
me.L3[2] = "blu";
me.L6 = [" RETURN", nil, "wht"];
me.R6 = [nil, nil, "ack"];
me.arrowsColour[0][5] = "wht";
me.titleColour = "wht";
canvas_mcdu.pageSwitch[me.computer].setBoolValue(0);
}
}
},
pushbuttonLeft: func(index) {
me.scratchpad = mcdu_scratchpad.scratchpads[me.computer].scratchpad;
if (index == 1) {
if (size(me.scratchpad) <= 3 and num(me.scratchpad) != nil) {
me.waypoint.hold_inbound_radial = me.scratchpad;
mcdu_scratchpad.scratchpads[me.computer].empty();
me._setupPageWithData();
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
} else if (index == 2) {
if (me.scratchpad == "L") {
me.waypoint.hold_is_left_handed = 1;
mcdu_scratchpad.scratchpads[me.computer].empty();
me._setupPageWithData();
} elsif (me.scratchpad == "R") {
me.waypoint.hold_is_left_handed = 0;
mcdu_scratchpad.scratchpads[me.computer].empty();
me._setupPageWithData();
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
} elsif (index == 3) {
if (num(me.scratchpad) != nil) {
me.waypoint.hold_time_or_distance = me.scratchpad;
mcdu_scratchpad.scratchpads[me.computer].empty();
me._setupPageWithData();
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
},
pushbuttonRight: func(index) {
me.scratchpad = mcdu_scratchpad.scratchpads[me.computer].scratchpad;
if (size(me.scratchpad) != 0) {
mcdu_message(me.computer, "NOT ALLOWED");
} else {
if (index == 6) {
if (fmgc.flightPlanController.temporaryFlag[me.computer]) {
setprop("/MCDU[" ~ me.computer ~ "]/page", "F-PLNA");
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
} else {
mcdu_message(me.computer, "NOT ALLOWED");
}
}
},
};

View file

@ -79,20 +79,23 @@ var initInputA = func(key, i) {
#setprop("MCDU[" ~ i ~ "]/page", "ROUTESELECTION");
} else if (fmgc.FMGCInternal.toFromSet) {
if (!fmgc.flightPlanController.temporaryFlag[i]) {
var tfs = size(scratchpad);
if (tfs == 4) {
fmgc.FMGCInternal.altAirport = scratchpad;
fmgc.FMGCInternal.altAirportSet = 1;
atsu.ATISInstances[2].newStation(scratchpad);
fmgc.windController.updatePlans();
if (fmgc.FMGCInternal.blockConfirmed) {
fmgc.FMGCInternal.fuelCalculating = 0;
fmgc.fuelCalculating.setValue(0);
fmgc.FMGCInternal.fuelCalculating = 1;
fmgc.fuelCalculating.setValue(1);
if (size(scratchpad) == 4) {
if (size(findAirportsByICAO(scratchpad)) > 0) {
fmgc.FMGCInternal.altAirport = scratchpad;
fmgc.FMGCInternal.altAirportSet = 1;
atsu.ATISInstances[2].newStation(scratchpad);
fmgc.windController.updatePlans();
if (fmgc.FMGCInternal.blockConfirmed) {
fmgc.FMGCInternal.fuelCalculating = 0;
fmgc.fuelCalculating.setValue(0);
fmgc.FMGCInternal.fuelCalculating = 1;
fmgc.fuelCalculating.setValue(1);
}
mcdu_scratchpad.scratchpads[i].empty();
fmgc.updateARPT();
} else {
mcdu_message(i, "NOT IN DATA BASE");
}
mcdu_scratchpad.scratchpads[i].empty();
fmgc.updateARPT();
#fmgc.FMGCInternal.altSelected = 1;
#setprop("MCDU[" ~ i ~ "]/page", "ROUTESELECTION");
} else {
@ -249,25 +252,26 @@ var initInputA = func(key, i) {
#setprop("MCDU[" ~ i ~ "]/page", "ROUTESELECTION");
} else {
if (!fmgc.flightPlanController.temporaryFlag[i]) {
var tfs = size(scratchpad);
if (tfs == 9 and find("/", scratchpad) != -1) {
if (size(scratchpad) == 9 and find("/", scratchpad) != -1) {
var fromto = split("/", scratchpad);
var froms = size(fromto[0]);
var tos = size(fromto[1]);
if (froms == 4 and tos == 4) {
resetFlightplan(i);
fmgc.FMGCInternal.depApt = fromto[0];
fmgc.FMGCInternal.arrApt = fromto[1];
atsu.ATISInstances[0].newStation(fromto[0]);
atsu.ATISInstances[1].newStation(fromto[1]);
fmgc.FMGCInternal.toFromSet = 1;
fmgc.FMGCNodes.toFromSet.setValue(1);
mcdu_scratchpad.scratchpads[i].empty();
fmgc.flightPlanController.updateAirports(fromto[0], fromto[1], 2);
fmgc.FMGCInternal.altSelected = 0;
fmgc.updateARPT();
fmgc.updateArptLatLon();
if (size(fromto[0]) == 4 and size(fromto[1]) == 4) {
if (size(findAirportsByICAO(fromto[0])) > 0 and size(findAirportsByICAO(fromto[1])) > 0) {
resetFlightplan(i);
fmgc.FMGCInternal.depApt = fromto[0];
fmgc.FMGCInternal.arrApt = fromto[1];
atsu.ATISInstances[0].newStation(fromto[0]);
atsu.ATISInstances[1].newStation(fromto[1]);
fmgc.FMGCInternal.toFromSet = 1;
fmgc.FMGCNodes.toFromSet.setValue(1);
mcdu_scratchpad.scratchpads[i].empty();
fmgc.flightPlanController.updateAirports(fromto[0], fromto[1], 2);
fmgc.FMGCInternal.altSelected = 0;
fmgc.updateARPT();
fmgc.updateArptLatLon();
} else {
mcdu_message(i, "NOT IN DATA BASE");
}
#setprop("MCDU[" ~ i ~ "]/page", "ROUTESELECTION");
} else {
mcdu_message(i, "NOT ALLOWED");

View file

@ -6,6 +6,7 @@
var pageNode = [props.globals.getNode("/MCDU[0]/page"), props.globals.getNode("/MCDU[1]/page")];
var page = nil;
var msg = nil;
var airportPress = [0,0];
var scratchpadNode = [nil, nil];
var MCDU_init = func(i) {
@ -68,7 +69,7 @@ var MCDU_reset = func(i) {
fmgc.FMGCInternal.depApt = "";
fmgc.FMGCInternal.flightNum = "";
fmgc.FMGCInternal.flightNumSet = 0;
fmgc.FMGCInternal.gndTemp = -99;
fmgc.FMGCInternal.gndTemp = 15;
fmgc.FMGCInternal.gndTempSet = 0;
fmgc.FMGCInternal.toFromSet = 0;
fmgc.FMGCNodes.toFromSet.setValue(0);
@ -356,6 +357,8 @@ var lskbutton = func(btn, i) {
mcdu_scratchpad.scratchpads[i].empty();
}
}
} else if (page == "HOLD") {
canvas_mcdu.myHold[i].pushbuttonLeft(1);
} else if (page == "MCDUTEXT") {
atsu.freeTexts[i].selection = 0;
atsu.freeTexts[i].changed = 1;
@ -503,6 +506,8 @@ var lskbutton = func(btn, i) {
}
} else if (page == "VERTREV") {
canvas_mcdu.myVertRev[i].pushButtonLeft(2);
} else if (page == "HOLD") {
canvas_mcdu.myHold[i].pushbuttonLeft(2);
} else if (page == "MCDUTEXT") {
atsu.freeTexts[i].selection = 1;
atsu.freeTexts[i].changed = 1;
@ -631,6 +636,8 @@ var lskbutton = func(btn, i) {
}
} else if (page == "VERTREV") {
canvas_mcdu.myVertRev[i].pushButtonLeft(3);
} else if (page == "HOLD") {
canvas_mcdu.myHold[i].pushbuttonLeft(3);
} else if (page == "MCDUTEXT") {
atsu.freeTexts[i].selection = 2;
atsu.freeTexts[i].changed = 1;
@ -848,6 +855,8 @@ var lskbutton = func(btn, i) {
} else {
if (canvas_mcdu.myDuplicate[i] != nil and canvas_mcdu.myDuplicate[i].flagPROG) {
pagebutton("prog",i);
} else {
pageNode[i].setValue("F-PLNA");
}
}
} else if (page == "ARRIVAL") {
@ -1499,25 +1508,32 @@ var pagebutton = func(btn, i) {
} else if (btn == "mcdu") {
mcdu_message(i, "SELECT DESIRED SYSTEM");
pageNode[i].setValue("MCDU");
} else if (btn == "f-pln" or btn == "airport") {
} else if (btn == "f-pln") {
if (canvas_mcdu.myFpln[i] == nil) {
canvas_mcdu.myFpln[i] = fplnPage.new(2, i);
}
if (btn == "airport") {
if (fmgc.FMGCInternal.phase == 0 or fmgc.FMGCInternal.phase == 1) {
canvas_mcdu.myFpln[i].scroll = 0;
} else {
if (fmgc.flightPlanController.temporaryFlag[i]) {
canvas_mcdu.myFpln[i].scroll = fmgc.flightPlanController.arrivalIndex[i];
canvas_mcdu.myFpln[i].scroll = 0;
pageNode[i].setValue("F-PLNA");
} else if (btn == "airport") {
if (airportPress[i] == 0 or fmgc.FMGCInternal.phase >= 1) {
if (fmgc.flightPlanController.temporaryFlag[i]) {
if (fmgc.flightPlanController.currentToWptIndex.getValue() == fmgc.flightPlanController.arrivalIndex[i]) {
canvas_mcdu.myFpln[i].scroll = (fmgc.flightPlanController.arrivalIndex[i] - fmgc.flightPlanController.currentToWptIndex.getValue());
} else {
canvas_mcdu.myFpln[i].scroll = fmgc.flightPlanController.arrivalIndex[2];
canvas_mcdu.myFpln[i].scroll = (fmgc.flightPlanController.arrivalIndex[i] - fmgc.flightPlanController.currentToWptIndex.getValue()) - 1;
}
} else {
if (fmgc.flightPlanController.currentToWptIndex.getValue() == fmgc.flightPlanController.arrivalIndex[2]) {
canvas_mcdu.myFpln[i].scroll = (fmgc.flightPlanController.arrivalIndex[2] - fmgc.flightPlanController.currentToWptIndex.getValue());
} else {
canvas_mcdu.myFpln[i].scroll = (fmgc.flightPlanController.arrivalIndex[2] - fmgc.flightPlanController.currentToWptIndex.getValue()) - 1;
}
}
} else {
airportPress[i] = 1;
} else if (fmgc.FMGCInternal.phase == 0 or fmgc.FMGCInternal.phase == 1) {
canvas_mcdu.myFpln[i].scroll = 0;
airportPress[i] = 0;
}
pageNode[i].setValue("F-PLNA");
} else if (btn == "fuel-pred") {
pageNode[i].setValue("FUELPRED");
} else if (btn == "dirto") {

View file

@ -39,6 +39,7 @@ var perfCLBInput = func(key, i) {
setprop("/FMGC/internal/activate-twice", 1);
fmgc.FMGCInternal.phase = 5;
fmgc.FMGCInternal.decel = 1;
setprop("/instrumentation/nd/symbols/decel/show", 0);
setprop("MCDU[" ~ i ~ "]/page", "PERFAPPR");
} else {
mcdu_message(i, "NOT ALLOWED");

View file

@ -33,6 +33,7 @@ var perfCRZInput = func(key, i) {
setprop("/FMGC/internal/activate-twice", 1);
fmgc.FMGCInternal.phase = 5;
fmgc.FMGCInternal.decel = 1;
setprop("/instrumentation/nd/symbols/decel/show", 0);
setprop("MCDU[" ~ i ~ "]/page", "PERFAPPR");
} else {
mcdu_message(i, "NOT ALLOWED");

View file

@ -33,6 +33,7 @@ var perfDESInput = func(key, i) {
setprop("/FMGC/internal/activate-twice", 1);
fmgc.FMGCInternal.phase = 5;
fmgc.FMGCInternal.decel = 1;
setprop("/instrumentation/nd/symbols/decel/show", 0);
setprop("MCDU[" ~ i ~ "]/page", "PERFAPPR");
} else {
mcdu_message(i, "NOT ALLOWED");

View file

@ -1,3 +1,6 @@
# A3XX MCDU Received Messages Page
# Copyright (c) 2022 Jonathan Redpath (legoboyvdlp)
var receivedMessagesPage = {
title: nil,
arrowsMatrix: [[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]],

View file

@ -434,6 +434,24 @@
</period>
</filter>
<filter>
<name>Get Back on Magenta</name>
<type>gain</type>
<gain>
<expression>
<table>
<property>/fdm/jsbsim/velocities/vc-kts</property>
<entry><ind>140</ind><dep>50</dep></entry>
<entry><ind>360</ind><dep>20</dep></entry>
</table>
</expression>
</gain>
<input>/instrumentation/gps/wp/wp[1]/course-error-nm</input>
<output>/it-autoflight/internal/course-error-deg</output>
<min>-45</min>
<max>45</max>
</filter>
<filter>
<name>Heading Error Deg</name>
<type>gain</type>
@ -485,7 +503,8 @@
</condition>
<expression>
<sum>
<property>/FMGC/flightplan[2]/current-leg-course</property>
<property>/instrumentation/gps/wp/leg-true-course-deg</property>
<property>/it-autoflight/internal/course-error-deg</property>
<product>
<property>/it-autoflight/internal/drift-angle-deg</property>
<value>-1.0</value>