1
0
Fork 0
fgdata/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas

791 lines
27 KiB
Text
Raw Normal View History

2018-02-26 21:24:21 +00:00
# Copyright 2018 Stuart Buchanan
# This file is part of FlightGear.
#
# Foobar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# FlightGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# PFDInstruments
var PFDInstruments =
{
COLORS : {
green : [0, 1, 0],
white : [1, 1, 1],
black : [0, 0, 0],
lightblue : [0, 1, 1],
darkblue : [0, 0, 1],
red : [1, 0, 0],
magenta : [1, 0, 1],
},
CDI_SOURCE : [ "GPS", "NAV1", "NAV2" ],
BRG_SOURCE : ["OFF", "NAV1", "NAV2", "GPS", "ADF"],
2018-02-26 21:24:21 +00:00
new : func (mfd, myCanvas, device, svg)
{
var obj = {
parents : [
PFDInstruments,
MFDPage.new(mfd, myCanvas, device, svg, "PFDInstruments", "PFD Instruments")
],
_ias_already_exceeded : 0,
_windDataDisplay : 0,
_CDISource : "GPS",
2018-02-26 21:24:21 +00:00
_BRG1 : "OFF",
_BRG2 : "OFF",
_DME : 0,
_OMI : "",
_Map : 0,
_Multiline : 0,
_annunciation : 0,
2018-02-26 21:24:21 +00:00
};
# Hide various elements for the moment. TODO - implement
obj.device.svg.getElementById("PFDInstrumentsFailures").setVisible(0);
obj.device.svg.getElementById("PFDInstrumentsGSPD").setVisible(0);
obj.addTextElements([
"Speed110",
"VSIText",
"TAS-text", "GSPD-text",
"Alt11100",
"AltBigC", "AltSmallC",
"BARO-text", "OAT-text",
"HDG-text",
"SelectedHDG-text",
"SelectedALT-text",
]);
# Set clipping for the various tapes
var clips = {
PitchScale : "rect(70,664,370,256)",
SpeedLint1 : "rect(252,226,318,204)",
SpeedTape : "rect(115,239,455,156)",
LintAlt : "rect(115,808,455,704)",
AltLint00011 : "rect(252,804,318,771)",
};
foreach(var id; keys(clips)) {
var clip = clips[id];
obj.device.svg.getElementById("PFDInstruments" ~ id).set("clip", clip);
}
#obj.insetMap = fg1000.NavMap.new(obj, [130,170], "rect(-160px, 160px, 160px, -160px)", -100, 2);
obj._SVGGroup.setInt("z-index", 10);
#obj._SVGGroup.setVisible(0);
#obj.insetMap = fg1000.NavMap.new(obj, [119,601], "rect(-109px, 109px, 109px, -109px)", 50, 2);
obj.insetMap = fg1000.NavMap.new(obj, obj.getElement("PFD-Map-Display"), [119,601], "rect(-109px, 109px, 109px, -109px)", 0, 2);
2018-02-26 21:24:21 +00:00
2018-02-27 19:57:45 +00:00
#obj.topMenu(device, obj, nil);
2018-02-26 21:24:21 +00:00
obj.setController(fg1000.PFDInstrumentsController.new(obj, svg));
obj.setWindDisplay(0);
obj.setCDISource("GPS");
2018-02-26 21:24:21 +00:00
obj.setBRG1("OFF");
obj.setBRG2("OFF");
obj.setDME(0);
obj.setMap(0);
obj.setMultiline(0);
obj.setAnnunciation(0);
obj.setOMI("");
obj.setInsetMapVisible(0);
obj.updateHDG(0);
obj.updateSelectedALT(0);
obj.updateCRS(0);
2018-02-26 21:24:21 +00:00
return obj;
},
2018-02-27 19:57:45 +00:00
topMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
pg.addMenuItem(1, "INSET", pg, pg.mfd.PFDInstruments.insetMenu);
2018-02-27 19:57:45 +00:00
pg.addMenuItem(3, "PFD", pg, pg.mfd.PFDInstruments.PFDMenu);
pg.addMenuItem(4, "OBS", pg); # TODO
pg.addMenuItem(5, "CDI", pg, pg.incrCDI);
#pg.addMenuItem(6, "DME", pg, func(dev, pg, mi) { pg.toggleDME(); } ); # TODO
2018-02-27 19:57:45 +00:00
pg.addMenuItem(7, "XPDR", pg); # TODO
pg.addMenuItem(8, "IDENT", pg); # TODO
pg.addMenuItem(9, "TMR/REF", pg); # TODO
pg.addMenuItem(10, "NRST", pg); # TODO
pg.addMenuItem(11, "ALERTS", pg); # TODO
device.updateMenus();
},
incrCDI : func(dev, pg, mi) {
var idx = -1;
for (var i = 0; i < size(PFDInstruments.CDI_SOURCE); i = i + 1) {
if (PFDInstruments.CDI_SOURCE[i] == pg._CDISource) {
idx = i;
break;
}
}
if (idx == -1) die("Unabled to increment CDI. _CDISource:" ~ me._CDISource);
idx = math.mod(idx + 1, size(PFDInstruments.CDI_SOURCE));
pg.setCDISource(PFDInstruments.CDI_SOURCE[idx]);
},
insetMenu : func(device, pg, menuitem) {
# Switch on the inset Map
pg.setInsetMapVisible(1);
pg.clearMenu();
pg.resetMenuColors();
pg.addMenuItem(0, "OFF", pg, func(dev, pg, mi) { pg.setInsetMapVisible(0); }); # TODO
pg.addMenuItem(1, "DCLTR", pg,
func(dev, pg, mi) { pg.insetMap.incrDCLTR(dev, mi); device.updateMenus(); },
func(svg, mi) { pg.displayDCLTR(svg, mi); },
);
#pg.addMenuItem(2, "WXLGND", pg); # Optional
# TODO: Support TRFC-1 to add traffic layer, TRFC-2 to just display a traffic map
pg.addMenuItem(3, "TRAFFIC", pg,
func(dev, pg, mi) { pg.insetMap.toggleLayer("TFC"); device.updateMenus(); }, # callback
func(svg, mi) { pg.display_toggle(device, svg, mi, "TFC"); }
);
pg.addMenuItem(4, "TOPO", pg,
func(dev, pg, mi) { pg.insetMap.toggleLayer("STAMEN"); device.updateMenus(); }, # callback
func(svg, mi) { pg.display_toggle(device, svg, mi, "STAMEN"); }
);
pg.addMenuItem(5, "TERRAIN", pg,
func(dev, pg, mi) { pg.insetMap.toggleLayer("STAMEN_terrain"); device.updateMenus(); }, # callback
func(svg, mi) { pg.display_toggle(device, svg, mi, "STAMEN_terrain"); }
);
#pg.addMenuItem(6, "STRMSCP", pg); # TODO
#pg.addMenuItem(7, "NEXRAD", pg); # TODO
#pg.addMenuItem(8, "XM LTNG", pg); # TODO
#pg.addMenuItem(9, "METAR", pg); # TODO
pg.addMenuItem(10, "BACK", pg, pg.mfd.PFDInstruments.topMenu);
pg.addMenuItem(11, "ALERTS", pg); # TODO
device.updateMenus();
},
displayDCLTR : func(svg, mi) {
mi.title = me.insetMap.getDCLTRTitle();
svg.setText(mi.title);
svg.setVisible(1);
},
# Display map toggle softkeys which change color depending
# on whether a particular layer is enabled or not.
display_toggle : func(device, svg, mi, layer) {
var bg_name = sprintf("SoftKey%d-bg",mi.menu_id);
if (me.insetMap.isEnabled(layer)) {
device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5);
svg.setColor(0.0,0.0,0.0);
} else {
device.svg.getElementById(bg_name).setColorFill(0.0,0.0,0.0);
svg.setColor(1.0,1.0,1.0);
}
svg.setText(mi.title);
svg.setVisible(1); # display function
},
2018-02-27 19:57:45 +00:00
PFDMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
pg.addMenuItem(0, "SYN VIS", pg); # TODO
pg.addMenuItem(1, "DFLTS", pg);
pg.addMenuItem(2, "WIND", pg, pg.mfd.PFDInstruments.windMenu);
#pg.addMenuItem(3, "DME", pg); # TODO
pg.addMenuItem(4, "BRG1", pg, pg.mfd.PFDInstruments.incrBRG1); # TODO
2018-02-27 19:57:45 +00:00
pg.addMenuItem(5, "HSI FRMT", pg); # TODO
pg.addMenuItem(6, "BRG2", pg, pg.mfd.PFDInstruments.incrBRG2); # TODO
2018-02-27 19:57:45 +00:00
#pg.addMenuItem(8, "IDENT", pg); # TODO
pg.addMenuItem(8, "ALT UNIT ", pg); # TODO
pg.addMenuItem(9, "STD BARO", pg, func(dev, pg, mi) { pg.getController().setStdBaro(); } );
2018-02-27 19:57:45 +00:00
pg.addMenuItem(10, "BACK", pg, pg.mfd.PFDInstruments.topMenu);
pg.addMenuItem(11, "ALERTS", pg); # TODO
device.updateMenus();
},
incrBRG1 : func(dev, pg, mi) { pg.mfd.PFDInstruments.incrBRG("BRG1"); },
incrBRG2 : func(dev, pg, mi) { pg.mfd.PFDInstruments.incrBRG("BRG2"); },
incrBRG : func(brg) {
var curr = (brg == "BRG1" ? me.getBRG1() : me.getBRG2());
var idx = -1;
for (var i = 0; i < size(PFDInstruments.BRG_SOURCE); i = i + 1) {
if (PFDInstruments.BRG_SOURCE[i] == curr) {
idx = i;
break;
}
}
if (idx == -1) die("Unabled to increment BRG. curr:" ~ curr);
idx = math.mod(idx + 1, size(PFDInstruments.BRG_SOURCE));
if (brg == "BRG1") {
me.setBRG1(PFDInstruments.BRG_SOURCE[idx]);
} else {
me.setBRG2(PFDInstruments.BRG_SOURCE[idx]);
}
},
2018-02-27 19:57:45 +00:00
windMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
pg.addMenuItem(2, "OPTN1", pg,
func(dev, pg, mi) { pg.mfd.PFDInstruments.setWindDisplay(1); device.updateMenus(); }, # Action callback
func(svg, mi) { pg.mfd.PFDInstruments.toggleWindDisplay(device, svg, mi, 1); } # Display callback
);
pg.addMenuItem(3, "OPTN2", pg,
func(dev, pg, mi) { pg.mfd.PFDInstruments.setWindDisplay(2); device.updateMenus(); }, # Action callback
func(svg, mi) { pg.mfd.PFDInstruments.toggleWindDisplay(device, svg, mi, 2); } # Display callback
);
pg.addMenuItem(4, "OPTN3", pg,
func(dev, pg, mi) { pg.mfd.PFDInstruments.setWindDisplay(3); device.updateMenus(); }, # Action callback
func(svg, mi) { pg.mfd.PFDInstruments.toggleWindDisplay(device, svg, mi, 3); } # Display callback
);
pg.addMenuItem(5, "OFF", pg,
func(dev, pg, mi) { pg.mfd.PFDInstruments.setWindDisplay(0); device.updateMenus(); }, # Action callback
func(svg, mi) { pg.mfd.PFDInstruments.toggleWindDisplay(device, svg, mi, 0); } # Display callback
);
pg.addMenuItem(10, "BACK", pg, pg.mfd.PFDInstruments.topMenu);
pg.addMenuItem(11, "ALERTS", pg); # TODO
device.updateMenus();
},
toggleWindDisplay : func(device, svg, mi, wind_value) {
var bg_name = sprintf("SoftKey%d-bg",mi.menu_id);
if (me._windDataDisplay == wind_value) {
device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5);
svg.setColor(0.0,0.0,0.0);
} else {
device.svg.getElementById(bg_name).setColorFill(0.0,0.0,0.0);
svg.setColor(1.0,1.0,1.0);
}
svg.setText(mi.title);
svg.setVisible(1); # display function
},
2018-02-26 21:24:21 +00:00
offdisplay : func() {
me._group.setVisible(0);
# Reset the menu colours. Shouldn't have to do this here, but
# there's not currently an obvious other location to do so.
for(var i = 0; i < 12; i +=1) {
var name = sprintf("SoftKey%d",i);
me.device.svg.getElementById(name ~ "-bg").setColorFill(0.0,0.0,0.0);
me.device.svg.getElementById(name).setColor(1.0,1.0,1.0);
}
me.getController().offdisplay();
},
ondisplay : func() {
me._group.setVisible(1);
me.mfd.setPageTitle(me.title);
me.getController().ondisplay();
},
updateAI: func(pitch, roll, slip) {
if (pitch > 80)
pitch = 80;
elsif (pitch < -80)
pitch = -80;
me.getElement("Horizon")
.setCenter(459, 282.8 - 6.849 * pitch)
.setRotation(-roll * D2R)
.setTranslation(0, pitch * 6.849);
me.getElement("bankPointer")
.setRotation(-roll * D2R);
me.getElement("SlipSkid")
.setTranslation(slip * 10, 0);
},
updateIAS: func (ias, ias_trend) {
if (ias >= 10) {
me.setTextElement("Speed110", sprintf("% 2u",num(math.floor(ias/10))));
} else {
me.setTextElement("Speed110", "");
}
me.getElement("SpeedLint1").setTranslation(0,(math.mod(ias,10) + (ias >= 10)*10) * 36);
me.getElement("SpeedTape").setTranslation(0,ias * 5.711);
ias_trend = math.clamp(ias_trend, -30, 30);
me.getElement("Airspeed-Trend-Indicator")
.setScale(1,ias_trend)
.setTranslation(0, -284.5 * (ias_trend - 1));
var vne = me.mfd.ConfigStore.get("Vne");
if (ias > vne and ! me._ias_already_exceeded) {
me._ias_already_exceeded = 1;
me.getElement("IAS-bg").setColorFill(1,0,0);
} elsif (ias < vne and me._ias_already_exceeded) {
me._ias_already_exceeded = 0;
me.getElement("IAS-bg").setColorFill(0,0,0);
}
foreach (var v; ["Vx", "Vy", "Vr", "Vglide"]) {
var spd = me.mfd.ConfigStore.get(v);
var visible = me.mfd.ConfigStore.get(v ~ "-visible");
if (visible and abs(spd - ias) < 30) {
me.getElement("IAS-" ~ v)
.setTranslation(0, (ias - spd) * 5.711)
.show();
} else {
me.getElement("IAS-" ~ v).hide();
}
}
},
updateVSI: func (vsi) {
me.getElement("VSI").setTranslation(0, math.clamp(vsi, -4500, 4500) * -0.03465);
me.setTextElement("VSIText", num(math.round(vsi, 10)));
},
updateTAS: func (tas) {
me.setTextElement("TAS-text", sprintf("%iKT", tas));
#me.getElement("GSPD-text").setText(sprintf("%iKT", tas));
},
updateALT: func (alt, alt_trend, selected_alt) {
if (alt < 0) {
me.setTextElement("Alt11100", sprintf("-% 3i",abs(math.ceil(alt/100))));
} elsif (alt < 100) {
me.setTextElement("Alt11100", "");
} else {
me.setTextElement("Alt11100", sprintf("% 3i",math.floor(alt/100)));
}
me.getElement("AltLint00011").setTranslation(0,math.fmod(alt,100) * 1.24);
if (alt> -1000 and alt< 1000000) {
var Offset10 = 0;
var Offset100 = 0;
var Offset1000 = 0;
var Ne = 0;
var Alt10 = math.mod(alt,100);
var Alt100 = int(math.mod(alt/100,10));
var Alt1000 = int(math.mod(alt/1000,10));
var Alt10000 = int(math.mod(alt/10000,10));
var Alt20 = math.mod(Alt10,20)/20;
if (alt< 0) {
var Ne = 1;
var alt= -alt;
}
if (Alt10 >= 80) Alt100 += Alt20;
if (Alt10 >= 80 and Alt100 >= 9) Alt1000 += Alt20;
if (Alt10 >= 80 and Alt100 >= 9 and Alt1000 >= 9) Alt10000 += Alt20;
if (alt> 100) Offset10 = 100;
if (alt> 1000) Offset100 = 10;
if (alt> 10000) Offset1000 = 10;
if (Ne) {
me.getElement("LintAlt").setTranslation(0,(math.mod(alt,100))*-0.57375);
var altCentral = -(int(alt/100)*100);
} else {
me.getElement("LintAlt").setTranslation(0,(math.mod(alt,100))*0.57375);
var altCentral = (int(alt/100)*100);
}
me.setTextElement("AltBigC", "");
me.setTextElement("AltSmallC", "");
for (var place = 1; place <= 6; place += 1) {
var altUP = altCentral + (place*100);
var altDOWN = altCentral - (place*100);
var offset = -30.078;
var prefix = "";
if (altUP < 0) {
altUP = -altUP;
prefix = "-";
offset += 15.039;
}
var AltBigUP = "";
var AltSmallUP = "0";
if (altUP == 0) {
AltBigUP = "";
AltSmallUP = "0";
} elsif (math.mod(altUP,500) == 0 and altUP != 0) {
AltBigUP = sprintf(prefix~"%1d", altUP);
AltSmallUP = "";
} elsif (altUP < 1000 and (math.mod(altUP,500))) {
AltBigUP = "";
AltSmallUP = sprintf(prefix~"%1d", int(math.mod(altUP,1000)));
offset = -30.078;
} elsif ((altUP < 10000) and (altUP >= 1000) and (math.mod(altUP,500))) {
AltBigUP = sprintf(prefix~"%1d", int(altUP/1000));
AltSmallUP = sprintf("%1d", int(math.mod(altUP,1000)));
offset += 15.039;
} else {
AltBigUP = sprintf(prefix~"%1d", int(altUP/1000));
mod = int(math.mod(altUP,1000));
AltSmallUP = sprintf("%1d", mod);
offset += 30.078;
}
me.getElement("AltBigU"~place).setText(AltBigUP);
me.getElement("AltSmallU"~place).setText(AltSmallUP);
me.getElement("AltSmallU"~place).setTranslation(offset,0);
offset = -30.078;
prefix = "";
if (altDOWN < 0) {
altDOWN = -altDOWN;
prefix = "-";
offset += 15.039;
}
if (altDOWN == 0) {
AltBigDOWN = "";
AltSmallDOWN = "0";
} elsif (math.mod(altDOWN,500) == 0 and altDOWN != 0) {
AltBigDOWN = sprintf(prefix~"%1d", altDOWN);
AltSmallDOWN = "";
} elsif (altDOWN < 1000 and (math.mod(altDOWN,500))) {
AltBigDOWN = "";
AltSmallDOWN = sprintf(prefix~"%1d", int(math.mod(altDOWN,1000)));
offset = -30.078;
} elsif ((altDOWN < 10000) and (altDOWN >= 1000) and (math.mod(altDOWN,500))) {
AltBigDOWN = sprintf(prefix~"%1d", int(altDOWN/1000));
AltSmallDOWN = sprintf("%1d", int(math.mod(altDOWN,1000)));
offset += 15.039;
} else {
AltBigDOWN = sprintf(prefix~"%1d", int(altDOWN/1000));
AltSmallDOWN = sprintf("%1d", int(math.mod(altDOWN,1000)));
offset += 30.078;
}
me.getElement("AltBigD"~place).setText(AltBigDOWN);
me.getElement("AltSmallD"~place).setText(AltSmallDOWN);
me.getElement("AltSmallD"~place).setTranslation(offset,0);
}
}
alt_trend = math.clamp(alt_trend, -15, 15);
me.getElement("Altitude-Trend-Indicator")
.setScale(1,alt_trend)
.setTranslation(0, -284.5 * (alt_trend - 1));
var delta_alt = alt - selected_alt;
delta_alt = math.clamp(delta_alt, -300, 300);
me.getElement("SelectedALT-bug").setTranslation(0, delta_alt * 0.567); # 170/300 = 0.567
},
updateBARO : func (baro) {
# TODO: Support hPa and inhg
#var fmt = me._baro_unit == "inhg" ? "%.2fin" : "%i%shPa";
var fmt = "%.2fIN";
2018-02-26 21:24:21 +00:00
me.setTextElement("BARO-text", sprintf(fmt, baro));
},
updateOAT : func (oat) {
# TODO: Support FAHRENHEIT
me.setTextElement("OAT-text", sprintf((abs(oat) < 10) ? "%.1f %s" : "%i %s", oat, "°C"));
},
updateHSI : func (hdg) {
me.getElement("Rose").setRotation(-hdg * D2R);
me.setTextElement("HDG-text", sprintf("%03u°", hdg));
},
updateHDG : func (hdg) {
me.getElement("Heading-bug").setRotation(hdg * D2R);
me.setTextElement("SelectedHDG-text", sprintf("%03d°%s", hdg, ""));
},
# Indicate the selected course, from a given source (OFF, NAV, GPS)
updateCRS : func (crs) {
me.getElement("SelectedCRS-text")
.setText(sprintf("%03d°%s", crs, ""))
.setColor(me._CDISource == "GPS" ? me.COLORS.magenta : me.COLORS.green);
},
updateSelectedALT : func (selected_alt) {
me.setTextElement("SelectedALT-text", sprintf("%i", selected_alt));
},
# Bearing (BRG) settings
# "OFF", "NAV1", "NAV2", "GPS", "ADF"
getBRG1 : func() { return me._BRG1; },
getBRG2 : func() { return me._BRG2; },
setBRG1 : func(option) {
me._BRG1 = option;
me._setBRG("BRG1",option);
},
setBRG2 : func(option) {
me._BRG2 = option;
me._setBRG("BRG2",option);
},
_setBRG : func (brg, option) {
if (option == "OFF") {
me.getElement(brg).hide();
me.getElement(brg ~ "-pointer").hide();
if ((me._BRG1 == "OFF") and (me._BRG2 == "OFF")) {
2018-02-26 21:24:21 +00:00
me.getElement("BRG-circle").hide();
}
} else {
me.getElement(brg).show();
me.getElement(brg ~ "-pointer").show();
me.getElement("BRG-circle").show();
me.getElement(brg ~ "-SRC-text").setText(option);
me.getElement(brg ~ "-WPID-text").setText("----");
if (option == "ADF") {
# Special case. We won't have a distance and the "ID" will be the ADF
# frequency
me.getElement(brg ~ "-DST-text").setText("");
} else {
me.getElement(brg ~ "-DST-text").setText("--nm");
}
2018-02-26 21:24:21 +00:00
}
},
# Update BRG information
updateBRG1 : func(valid, id, dst, current_heading, brg_heading) {
me._updateBRG("BRG1", me._BRG1, valid, id, dst, current_heading, brg_heading);
2018-02-26 21:24:21 +00:00
},
updateBRG2 : func(valid, id, dst, current_heading, brg_heading) {
me._updateBRG("BRG2", me._BRG2, valid, id, dst, current_heading, brg_heading);
2018-02-26 21:24:21 +00:00
},
_updateBRG : func (brg, source, valid, id, dst, current_heading, brg_heading) {
2018-02-26 21:24:21 +00:00
if (source == "OFF") return;
if (valid) {
me.getElement(brg ~ "-SRC-text").setText(source);
me.getElement(brg ~ "-WPID-text").setText(id);
2018-02-26 21:24:21 +00:00
if (source == "ADF") {
# Special case. We won't have a distance and the "ID" will be the ADF
# frequency
me.getElement(brg ~ "-DST-text").setText("");
} else {
me.getElement(brg ~ "-DST-text").setText(sprintf("%.1fNM", dst));
}
var rot = (brg_heading - current_heading) * D2R;
me.getElement(brg ~ "-pointer").setRotation(rot).show();
2018-02-26 21:24:21 +00:00
} else {
# Data is not valid - hide the pointer and display NO DATA
me.getElement(brg ~ "-SRC-text").setText(source);
me.getElement(brg ~ "-WPID-text").setText("NO DATA");
me.getElement(brg ~ "-DST-text").setText("");
me.getElement(brg ~ "-pointer").hide();
2018-02-26 21:24:21 +00:00
}
},
toggleDME : func() {
me.setDME(! me._DME);
},
2018-02-26 21:24:21 +00:00
setDME : func (enabled) {
me._DME = enabled;
me.getElement("DME1").setVisible(enabled);
},
updateDME : func (mode, freq, dst) {
if (me._DME == 0) return;
me.getElement("DME1-SRC-text").setText(mode);
me.getElement("DME1-FREQ-text").setText(sprintf("%.2f", freq));
me.getElement("DME1-DST-text").setText(sprintf("%.2fNM", dst));
},
setCDISource : func(source) {
if (source == "OFF") {
foreach (var s; ["GPS", "NAV1", "NAV2"]) {
foreach (var t; ["pointer", "CDI", "FROM", "TO"]) {
me.getElement(s ~ "-" ~ t).hide();
}
}
me.getElement("CDI-GPS-ANN-text").hide();
me.getElement("CDI-GPS-XTK-text").hide();
me.getElement("CDI-SRC-text").hide();
me.getElement("CDI").hide();
me.getElement("GPS-CTI-diamond").hide();
me.getElement("SelectedCRS").hide();
} else {
me.getElement("CDI").show();
me.getElement("SelectedCRS").show();
if (source == "GPS") {
me.getElement("CDI-GPS-ANN-text").show();
me.getElement("GPS-CTI-diamond").show();
} else {
me.getElement("CDI-GPS-ANN-text").hide();
me.getElement("GPS-CTI-diamond").hide();
}
# Localizers are mapped to the NAV1/2 elements, but have reduced deflection
# and a different label.
me.getElement("CDI-SRC-text")
.setText(source)
.setColor(source == "GPS" ? me.COLORS.magenta : me.COLORS.green)
.show();
if (source == "LOC1") source = "NAV1";
if (source == "LOC2") source = "NAV2";
foreach (var s; ["GPS", "NAV1", "NAV2"]) {
me.getElement(s ~ "-pointer").setVisible(source == s);
me.getElement(s ~ "-CDI").setVisible(source == s);
me.getElement(s ~ "-FROM").setVisible(source == s);
me.getElement(s ~ "-TO").setVisible(source == s);
}
}
me._CDISource = source;
},
updateCDI : func (heading, course, waypoint_valid, course_deviation_deg, deflection_dots, xtrk_nm, from, annun) {
2018-02-26 21:24:21 +00:00
if (me._CDISource == "OFF") return;
if (waypoint_valid == 0) {
me.getElement(me._CDISource ~ "-CDI").hide();
me.getElement(me._CDISource ~ "-FROM").hide();
me.getElement(me._CDISource ~ "-TO").hide();
me.getElement(me._CDISource ~ "-pointer").hide();
me.getElement("CDI").setRotation(0);
me.getElement("GPS-CTI-diamond").hide();
2018-02-26 21:24:21 +00:00
me.getElement("CDI-GPS-XTK-text").hide();
me.getElement("CDI-GPS-ANN-text").hide();
} else {
me.getElement(me._CDISource ~ "-CDI").show();
var rot = (course - heading) * D2R;
me.getElement("CDI").setRotation(rot).show();
me.getElement("GPS-CTI-diamond")
.setVisible(waypoint_valid)
.setRotation(course_deviation_deg * D2R);
if ((me._CDISource == "GPS") and (abs(deflection_dots) > 2.0)) {
# Only display the cross-track error if the error exceeds the maximum
# deflection of two dots.
me.getElement("CDI-GPS-XTK-text")
.setText(sprintf("XTK %.2fNM", abs(xtrk_nm)))
.show();
} else {
me.getElement("CDI-GPS-XTK-text").hide();
}
2018-02-26 21:24:21 +00:00
if (me._CDISource == "GPS") me.getElement("CDI-GPS-ANN-text").setText(annun).show();
2018-02-26 21:24:21 +00:00
var scale = math.clamp(deflection_dots, -2.4, 2.4);
me.getElement(me._CDISource ~ "-CDI").setTranslation(80 * scale / 2.4, 0);
# Display the appropriate TO/FROM indication for the selected source,
# switching all others off.
me.getElement(me._CDISource ~ "-TO").setVisible(from == 0);
me.getElement(me._CDISource ~ "-FROM").setVisible(from);
}
2018-02-26 21:24:21 +00:00
},
# Update the wind display. There are three options:
# 0 - No wind data displayed
# 1 - Numeric headwind and crosswind components
# 2 - Direction arrow and numeric speed
# 3 - Direction arrow, and numeric True direction and speet
setWindDisplay : func(option) {
me.getElement("WindData").setVisible(option != 0);
me.getElement("WindData-OPTN1").setVisible(option == 1);
me.getElement("WindData-OPTN2").setVisible(option == 2);
me.getElement("WindData-OPTN3").setVisible(option == 3);
me._windDataDisplay = option;
},
2018-02-27 19:57:45 +00:00
updateWindData : func (hdg, wind_hdg, wind_spd, no_data) {
if (no_data and (me._windDataDisplay > 0)) {
me.getElement("WindData-NODATA").show();
me.getElement("WindData-NODATA-bg").show();
2018-02-26 21:24:21 +00:00
return;
2018-02-27 19:57:45 +00:00
} else {
me.getElement("WindData-NODATA").hide();
me.getElement("WindData-NODATA-bg").hide();
2018-02-26 21:24:21 +00:00
}
2018-02-27 19:57:45 +00:00
var alpha = (wind_hdg - hdg);
2018-02-26 21:24:21 +00:00
2018-02-27 19:57:45 +00:00
# Stop the wind arrows oscillating
if (wind_spd < 1) {
alpha = 0;
wind_hdg = 0;
}
if (me._windDataDisplay == 0) {
me.getElement("WindData").hide();
} elsif (me._windDataDisplay == 1) {
# Headwind/Crosswind numeric display
var Vt = wind_spd * math.sin(alpha * D2R);
var Ve = wind_spd * math.cos(alpha * D2R);
me.getElement("WindData-OPTN1-crosswind-text").setText(sprintf("%i", abs(Vt)));
me.getElement("WindData-OPTN1-crosswind").setRotation(Vt > 0.1 ? 180*D2R : 0);
me.getElement("WindData-OPTN1-headwind-text").setText(sprintf("%i", abs(Ve)));
me.getElement("WindData-OPTN1-headwind").setRotation(Ve > 0.1 ? 180*D2R : 0);
2018-02-26 21:24:21 +00:00
} elsif (me._windDataDisplay == 2) {
# Direction arrow and numeric speed
me.getElement("WindData-OPTN2-HDG").setRotation((alpha + 180) * D2R);
2018-02-27 19:57:45 +00:00
me.getElement("WindData-OPTN2-SPD-text").setText(sprintf("%i", wind_spd));
2018-02-26 21:24:21 +00:00
} elsif (me._windDataDisplay == 3) {
# Direction arrow with numeric true direction and speed
me.getElement("WindData-OPTN3-HDG").setRotation((alpha + 180) * D2R);
me.getElement("WindData-OPTN3-HDG-text").setText(sprintf("%03i°T", wind_hdg));
2018-02-27 19:57:45 +00:00
me.getElement("WindData-OPTN3-SPD-text").setText(sprintf("%iKT", wind_spd));
2018-02-26 21:24:21 +00:00
} else {
print("Unknown wind data option " ~ me._windDataDisplay);
}
},
# Enable/disable the inset PFD Map.
setMap : func (enabled) {
me._Map = enabled;
me.getElement("PFD-Map").setVisible(enabled);
},
# Enable/disable the multiline display on the right hand side of the PFD
setMultiline : func(enabled) {
me._Multiline = enabled;
me.getElement("PFD-Multilines").setVisible(enabled);
},
# Enable/disable the warning annunication window.
setAnnunciation : func(enabled) {
me._annunciation = enabled;
me.getElement("Annunciation").setVisible(enabled);
},
# set the Outer, Middle, Inner indicator
setOMI : func(omi) {
if (omi == "") {
me.getElement("OMI").hide();
} else {
me.getElement("OMI").show();
me.getElement("MarkerText").setText(omi);
}
me._OMI = omi;
},
setInsetMapVisible :func(enabled ) {
me.getElement("PFD-Map").setVisible(enabled);
me.getElement("PFD-Map-bg").setVisible(enabled);
me.insetMap.setVisible(enabled);
},
2018-02-26 21:24:21 +00:00
};