FG1000 PFD Inset Map, HDG, BARO, ALT controls
- Add inset map for PFD - Add bindings to set the HDG, BARO, Altitude
This commit is contained in:
parent
e95dfc5b02
commit
c37f1ff7bb
14 changed files with 801 additions and 166 deletions
|
@ -24,11 +24,11 @@
|
||||||
borderopacity="1"
|
borderopacity="1"
|
||||||
inkscape:pageopacity="1"
|
inkscape:pageopacity="1"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="7.4375004"
|
inkscape:zoom="3.7187502"
|
||||||
inkscape:cx="279.11962"
|
inkscape:cx="99.463593"
|
||||||
inkscape:cy="261.78273"
|
inkscape:cy="150.41314"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="layer6"
|
inkscape:current-layer="svg3140"
|
||||||
showgrid="false"
|
showgrid="false"
|
||||||
showguides="false"
|
showguides="false"
|
||||||
inkscape:guide-bbox="true"
|
inkscape:guide-bbox="true"
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:type
|
<dc:type
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -6998,13 +6998,67 @@
|
||||||
id="PFDInstrumentsPFD-Map"
|
id="PFDInstrumentsPFD-Map"
|
||||||
inkscape:label="PFD-Map">
|
inkscape:label="PFD-Map">
|
||||||
<rect
|
<rect
|
||||||
inkscape:label="PFD-Map-bg"
|
style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
y="492"
|
id="PFDInstrumentsPFD-Map-bg-1"
|
||||||
x="13"
|
width="218.99536"
|
||||||
height="218"
|
height="218.99538"
|
||||||
width="215"
|
x="9.3594561"
|
||||||
id="PFD-Map-bg"
|
y="491.24179"
|
||||||
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
inkscape:label="PFD-Map-bg" />
|
||||||
|
<g
|
||||||
|
id="PFDInstrumentsPFD-Map-Display"
|
||||||
|
inkscape:label="#g14879">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:1.005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="PFDInstrumentsPFD-Map-bg"
|
||||||
|
width="218.99536"
|
||||||
|
height="218.99538"
|
||||||
|
x="9.5023146"
|
||||||
|
y="491.50232"
|
||||||
|
inkscape:label="PFD-Map-bg" />
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.97517461;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||||
|
id="PFDInstrumentsOrientation-bg"
|
||||||
|
width="79.886292"
|
||||||
|
height="21.989275"
|
||||||
|
x="146.78056"
|
||||||
|
y="492.74817"
|
||||||
|
inkscape:label="#rect14859" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
x="186.54517"
|
||||||
|
y="508.86316"
|
||||||
|
id="PFDInstrumentsOrientationDisplay"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
inkscape:label="#text14869"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan14871"
|
||||||
|
x="186.54517"
|
||||||
|
y="508.86316"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none">NORTH UP</tspan></text>
|
||||||
|
<rect
|
||||||
|
inkscape:label="#rect14859"
|
||||||
|
y="688.24396"
|
||||||
|
x="147.18393"
|
||||||
|
height="21.989275"
|
||||||
|
width="79.886292"
|
||||||
|
id="rect14873"
|
||||||
|
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.97517461;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
id="PFDInstrumentsRangeDisplay"
|
||||||
|
y="704.09003"
|
||||||
|
x="223.3855"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:label="#text14875"><tspan
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:end;writing-mode:lr-tb;text-anchor:end"
|
||||||
|
y="704.09003"
|
||||||
|
x="223.3855"
|
||||||
|
id="tspan14877"
|
||||||
|
sodipodi:role="line">15nm</tspan></text>
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
id="PFDInstrumentsBRG2"
|
id="PFDInstrumentsBRG2"
|
||||||
|
|
Before Width: | Height: | Size: 464 KiB After Width: | Height: | Size: 468 KiB |
|
@ -22,6 +22,36 @@
|
||||||
|
|
||||||
var ConfigStore = {
|
var ConfigStore = {
|
||||||
|
|
||||||
|
# Layer display configuration:
|
||||||
|
# enabled - whether this layer has been enabled by the user
|
||||||
|
# declutter - the maximum declutter level (0-3) that this layer is visible in
|
||||||
|
# range - the maximum range this layer is visible (configured by user)
|
||||||
|
# max_range - the maximum range value that a user can configure for this layer.
|
||||||
|
layerRanges : {
|
||||||
|
DTO : { enabled: 0, declutter: 3, range: 2000, max_range: 2000 },
|
||||||
|
|
||||||
|
GRID : { enabled: 0, declutter: 1, range: 20, max_range: 2000 },
|
||||||
|
DME : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
||||||
|
VOR_FG1000 : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
||||||
|
NDB : { enabled: 1, declutter: 1, range: 15, max_range: 30 },
|
||||||
|
FIX : { enabled: 1, declutter: 1, range: 15, max_range: 30 },
|
||||||
|
RTE : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
||||||
|
WPT : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
||||||
|
|
||||||
|
APS : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
||||||
|
FLT : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
||||||
|
|
||||||
|
WXR : { enabled: 1, declutter: 2, range: 2000, max_range: 2000 },
|
||||||
|
|
||||||
|
APT : { enabled: 1, declutter: 2, range: 150, max_range: 300 },
|
||||||
|
|
||||||
|
TFC : { enabled: 0, declutter: 3, range: 150, max_range: 2000},
|
||||||
|
|
||||||
|
OpenAIP : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
||||||
|
STAMEN : { enabled: 1, declutter: 3, range: 500, max_range: 2000 },
|
||||||
|
STAMEN_terrain : { enabled: 1, declutter: 3, range: 500, max_range: 2000 },
|
||||||
|
},
|
||||||
|
|
||||||
configValues : {
|
configValues : {
|
||||||
"DisplayUnitsNavAngle": ["MAGNETIC", "TRUE"] ,
|
"DisplayUnitsNavAngle": ["MAGNETIC", "TRUE"] ,
|
||||||
"DisplayUnitsDistanceAndSpeed": ["NAUTICAL", "METRIC"] ,
|
"DisplayUnitsDistanceAndSpeed": ["NAUTICAL", "METRIC"] ,
|
||||||
|
@ -91,6 +121,7 @@ var ConfigStore = {
|
||||||
var obj ={
|
var obj ={
|
||||||
parents : [ ConfigStore ],
|
parents : [ ConfigStore ],
|
||||||
_values : {},
|
_values : {},
|
||||||
|
_layerRanges : {},
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var i; keys(ConfigStore.configValues)) {
|
foreach (var i; keys(ConfigStore.configValues)) {
|
||||||
|
@ -107,6 +138,10 @@ var ConfigStore = {
|
||||||
#obj.set("MFDHeader4", "ESA");
|
#obj.set("MFDHeader4", "ESA");
|
||||||
obj.set("MFDHeader4", "FOD");
|
obj.set("MFDHeader4", "FOD");
|
||||||
|
|
||||||
|
foreach (var i; keys(ConfigStore.layerRanges)) {
|
||||||
|
obj._layerRanges[i] = ConfigStore.layerRanges[i];
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -140,4 +175,28 @@ var ConfigStore = {
|
||||||
get : func(name) {
|
get : func(name) {
|
||||||
return me._values[name];
|
return me._values[name];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getLayer : func(name) {
|
||||||
|
return me._layerRanges[name];
|
||||||
|
},
|
||||||
|
|
||||||
|
getLayerNames : func() {
|
||||||
|
return keys(me._layerRanges);
|
||||||
|
},
|
||||||
|
|
||||||
|
isLayerEnabled : func(name) {
|
||||||
|
return me._layerRanges[name].enabled;
|
||||||
|
},
|
||||||
|
setLayerEnabled : func(name, enabled) {
|
||||||
|
me._layerRanges[name].enabled = enabled;
|
||||||
|
},
|
||||||
|
toggleLayerEnabled : func(name) {
|
||||||
|
me._layerRanges[name].enabled = ! me._layerRanges[name].enabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
configureLayer : func(layer, enabled, range) {
|
||||||
|
me._layerRanges[layer].enabled = enabled;
|
||||||
|
me._layerRanges[layer].range = math.min(range, me._layerRanges[layer].max_range);
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -167,3 +167,43 @@ var SURFACE_TYPES = {
|
||||||
9 : "DIRT",
|
9 : "DIRT",
|
||||||
0 : "GRAVEL",
|
0 : "GRAVEL",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Vertical ranges, and labels.
|
||||||
|
# 28 ranges from 500ft to 2000nm, measuring the vertical map distance.
|
||||||
|
# Vertical size of the map (once the nav box and softkey area is removed) is 689px.
|
||||||
|
# 2000nm = 12,152,000ft.
|
||||||
|
var RANGES = [{range: 500/6076.12, label: "500ft"},
|
||||||
|
{range: 750/6076.12, label: "750ft"},
|
||||||
|
{range: 1000/6076.12, label: "1000ft"},
|
||||||
|
{range: 1500/6076.12, label: "1500ft"},
|
||||||
|
{range: 2000/6076.12, label: "2000ft"},
|
||||||
|
{range: 0.5, label: "0.5nm"},
|
||||||
|
{range: 0.75, label: "0.75nm"},
|
||||||
|
{range: 1, label: "1nm"},
|
||||||
|
{range: 2, label: "2nm"},
|
||||||
|
{range: 3, label: "3nm"},
|
||||||
|
{range: 4, label: "4nm"},
|
||||||
|
{range: 6, label: "6nm"},
|
||||||
|
{range: 8, label: "8nm"},
|
||||||
|
{range: 10, label: "10nm"},
|
||||||
|
{range: 12, label: "12nm"},
|
||||||
|
{range: 15, label: "15nm"},
|
||||||
|
{range: 20, label: "20nm"},
|
||||||
|
{range: 25, label: "25nm"},
|
||||||
|
{range: 30, label: "30nm"},
|
||||||
|
{range: 40, label: "40nm"},
|
||||||
|
{range: 50, label: "50nm"},
|
||||||
|
{range: 75, label: "75nm"},
|
||||||
|
{range: 100, label: "100nm"},
|
||||||
|
{range: 200, label: "200nm"},
|
||||||
|
{range: 500, label: "500nm"},
|
||||||
|
{range: 1000, label: "1000nm"},
|
||||||
|
{range: 1500, label: "1500nm"},
|
||||||
|
{range: 2000, label: "2000nm"}, ];
|
||||||
|
|
||||||
|
var ORIENTATIONS = [
|
||||||
|
{ label: "NORTH UP" },
|
||||||
|
{ label: "TRK UP" },
|
||||||
|
{ label: "DTK UP" },
|
||||||
|
{ label: "HDG UP" },
|
||||||
|
];
|
||||||
|
|
|
@ -31,6 +31,7 @@ io.load_nasal(nasal_dir ~ '/MFDPageController.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ '/PFD.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ '/PFD.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ '/MFD.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ '/MFD.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ '/GUI.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ '/GUI.nas', "fg1000");
|
||||||
|
io.load_nasal(nasal_dir ~ '/NavMap.nas', "fg1000");
|
||||||
|
|
||||||
var FG1000 = {
|
var FG1000 = {
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,17 @@ var GenericFMSPublisher =
|
||||||
obj.addPropMap("FMSHeadingBug", "/autopilot/settings/heading-bug-deg");
|
obj.addPropMap("FMSHeadingBug", "/autopilot/settings/heading-bug-deg");
|
||||||
obj.addPropMap("FMSSelectedAlt", "/autopilot/settings/target-alt-ft");
|
obj.addPropMap("FMSSelectedAlt", "/autopilot/settings/target-alt-ft");
|
||||||
|
|
||||||
|
obj.addPropMap("FMSLegValid", "/instrumentation/gps/wp/wp[1]/valid");
|
||||||
|
obj.addPropMap("FMSLegID", "/instrumentation/gps/wp/wp[1]/ID");
|
||||||
obj.addPropMap("FMSLegBearing", "/instrumentation/gps/wp/wp[1]/bearing-mag-deg");
|
obj.addPropMap("FMSLegBearing", "/instrumentation/gps/wp/wp[1]/bearing-mag-deg");
|
||||||
|
obj.addPropMap("FMSLegDistanceNM", "/instrumentation/gps/wp/wp[1]/distance-nm");
|
||||||
obj.addPropMap("FMSLegCourseError", "/instrumentation/gps/wp/wp[1]/course-error-nm");
|
obj.addPropMap("FMSLegCourseError", "/instrumentation/gps/wp/wp[1]/course-error-nm");
|
||||||
obj.addPropMap("FMSLegDesiredTrack", "/instrumentation/gps/indicated-track-magnetic-deg");
|
obj.addPropMap("FMSLegDesiredTrack", "/instrumentation/gps/wp/wp[1]/desired-course-deg");
|
||||||
obj.addPropMap("FMSLegTrackErrorAngle", "/instrumentation/gps/wp/wp[1]/course-deviation-deg");
|
obj.addPropMap("FMSLegTrackErrorAngle", "/instrumentation/gps/wp/wp[1]/course-deviation-deg");
|
||||||
obj.addPropMap("FMSLegTrack", "/instrumentation/gps/indicated-track-magnetic-deg");
|
|
||||||
obj.addPropMap("FMSGroundspeed", "/instrumentation/gps/indicated-ground-speed-kt");
|
|
||||||
obj.addPropMap("FMSWayPointCourseError", "/instrumentation/gps/wp/wp[1]/course-error-nm");
|
obj.addPropMap("FMSWayPointCourseError", "/instrumentation/gps/wp/wp[1]/course-error-nm");
|
||||||
|
|
||||||
|
obj.addPropMap("FMSGroundspeed", "/instrumentation/gps/indicated-ground-speed-kt");
|
||||||
|
|
||||||
obj.addPropMap("FMSNav1From", "/instrumentation/nav/from-flag");
|
obj.addPropMap("FMSNav1From", "/instrumentation/nav/from-flag");
|
||||||
obj.addPropMap("FMSNav2From", "/instrumentation/nav[1]/from-flag");
|
obj.addPropMap("FMSNav2From", "/instrumentation/nav[1]/from-flag");
|
||||||
|
|
||||||
|
@ -52,6 +55,11 @@ var GenericFMSPublisher =
|
||||||
gpsdata[name] = propmap.getValue();
|
gpsdata[name] = propmap.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Some GPS properties have odd values to indicate that nothing is set, so
|
||||||
|
# remove them from the data set.
|
||||||
|
if (gpsdata["FMSLegBearing"] == -9999) gpsdata["FMSLegBearing"] = nil;
|
||||||
|
if (gpsdata["FMSLegDistanceNM"] == -1) gpsdata["FMSLegDistanceNM"] = nil;
|
||||||
|
|
||||||
# A couple of calculated values used by the MFD Header display
|
# A couple of calculated values used by the MFD Header display
|
||||||
var total_fuel = getprop("/consumables/fuel/tank[0]/indicated-level-gal_us") or 0.0;
|
var total_fuel = getprop("/consumables/fuel/tank[0]/indicated-level-gal_us") or 0.0;
|
||||||
total_fuel = total_fuel + (getprop("/consumables/fuel/tank[1]/indicated-level-gal_us") or 0.0);
|
total_fuel = total_fuel + (getprop("/consumables/fuel/tank[1]/indicated-level-gal_us") or 0.0);
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# 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/>.
|
||||||
|
#
|
||||||
|
# FMS Interface using Emesary to update FMS properties from Emesary messages.
|
||||||
|
|
||||||
|
var GenericFMSUpdater =
|
||||||
|
{
|
||||||
|
new : func () {
|
||||||
|
var obj = {
|
||||||
|
parents : [
|
||||||
|
GenericFMSUpdater,
|
||||||
|
PropertyUpdater.new(
|
||||||
|
notifications.PFDEventNotification.DefaultType,
|
||||||
|
notifications.PFDEventNotification.FMSData,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
obj.addPropMap("FMSHeadingBug", "/autopilot/settings/heading-bug-deg");
|
||||||
|
obj.addPropMap("FMSSelectedAlt", "/autopilot/settings/target-alt-ft");
|
||||||
|
obj.addPropMap("FMSPressureSettingInHG", "/instrumentation/altimeter/setting-inhg");
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
};
|
|
@ -24,6 +24,7 @@ io.load_nasal(nasal_dir ~ 'Interfaces/GenericNavComPublisher.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ 'Interfaces/GenericNavComUpdater.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ 'Interfaces/GenericNavComUpdater.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ 'Interfaces/NavDataInterface.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ 'Interfaces/NavDataInterface.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSPublisher.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSPublisher.nas', "fg1000");
|
||||||
|
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSUpdater.nas', "fg1000");
|
||||||
io.load_nasal(nasal_dir ~ 'Interfaces/GenericADCPublisher.nas', "fg1000");
|
io.load_nasal(nasal_dir ~ 'Interfaces/GenericADCPublisher.nas', "fg1000");
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ var GenericInterfaceController = {
|
||||||
obj.navcomUpdater = fg1000.GenericNavComUpdater.new();
|
obj.navcomUpdater = fg1000.GenericNavComUpdater.new();
|
||||||
obj.navdataInterface = fg1000.NavDataInterface.new();
|
obj.navdataInterface = fg1000.NavDataInterface.new();
|
||||||
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
|
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
|
||||||
|
obj.gpsUpdater = fg1000.GenericFMSUpdater.new();
|
||||||
obj.adcPublisher = fg1000.GenericADCPublisher.new();
|
obj.adcPublisher = fg1000.GenericADCPublisher.new();
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
@ -62,6 +64,7 @@ var GenericInterfaceController = {
|
||||||
me.navcomUpdater.start();
|
me.navcomUpdater.start();
|
||||||
me.navdataInterface.start();
|
me.navdataInterface.start();
|
||||||
me.gpsPublisher.start();
|
me.gpsPublisher.start();
|
||||||
|
me.gpsUpdater.start();
|
||||||
me.adcPublisher.start();
|
me.adcPublisher.start();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -72,6 +75,7 @@ var GenericInterfaceController = {
|
||||||
me.navcomUpdater.stop();
|
me.navcomUpdater.stop();
|
||||||
me.navdataInterface.stop();
|
me.navdataInterface.stop();
|
||||||
me.gpsPublisher.stop();
|
me.gpsPublisher.stop();
|
||||||
|
me.gpsUpdater.stop();
|
||||||
me.adcPublisher.stop();
|
me.adcPublisher.stop();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -146,5 +146,14 @@ getDevice : func() {
|
||||||
getMFD : func() {
|
getMFD : func() {
|
||||||
return me.mfd;
|
return me.mfd;
|
||||||
},
|
},
|
||||||
|
getPageName : func () {
|
||||||
|
return me.pageName;
|
||||||
|
},
|
||||||
|
getSVG : func() {
|
||||||
|
return me._SVGGroup;
|
||||||
|
},
|
||||||
|
getGroup : func() {
|
||||||
|
return me._group;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,7 +44,7 @@ handleNavFreqTransfer : func (value) { return me.page.mfd.SurroundController.han
|
||||||
handleNavOuter : func (value) { return me.page.mfd.SurroundController.handleNavOuter(value); },
|
handleNavOuter : func (value) { return me.page.mfd.SurroundController.handleNavOuter(value); },
|
||||||
handleNavInner : func (value) { return me.page.mfd.SurroundController.handleNavInner(value); },
|
handleNavInner : func (value) { return me.page.mfd.SurroundController.handleNavInner(value); },
|
||||||
handleNavToggle : func (value) { return me.page.mfd.SurroundController.handleNavToggle(value); },
|
handleNavToggle : func (value) { return me.page.mfd.SurroundController.handleNavToggle(value); },
|
||||||
handleHeading : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleHeading : func (value) { return me.page.mfd.SurroundController.handleHeading(value); },
|
||||||
handleHeadingPress : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleHeadingPress : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
|
|
||||||
# Joystick
|
# Joystick
|
||||||
|
@ -53,7 +53,7 @@ handleJoystickHorizontal : func (value) { return emesary.Transmitter.ReceiptStat
|
||||||
handleJoystickHorizontal : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleJoystickHorizontal : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
|
|
||||||
#CRS/BARO
|
#CRS/BARO
|
||||||
handleBaro : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleBaro : func (value) { return me.page.mfd.SurroundController.handleBaro(value); },
|
||||||
handleCRS : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleCRS : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
handleCRSCenter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleCRSCenter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
|
|
||||||
|
@ -94,8 +94,8 @@ handleMenu : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcess
|
||||||
handleProc : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleProc : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
handleEnter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleEnter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
||||||
|
|
||||||
handleAltOuter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleAltOuter : func (value) { return me.page.mfd.SurroundController.handleAltOuter(value); },
|
||||||
handleAltInner : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
|
handleAltInner : func (value) { return me.page.mfd.SurroundController.handleAltInner(value); },
|
||||||
|
|
||||||
RegisterWithEmesary : func()
|
RegisterWithEmesary : func()
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,75 +17,7 @@
|
||||||
# Navigation Map Controller
|
# Navigation Map Controller
|
||||||
var NavigationMapController =
|
var NavigationMapController =
|
||||||
{
|
{
|
||||||
# Vertical ranges, and labels.
|
|
||||||
# 28 ranges from 500ft to 2000nm, measuring the vertical map distance.
|
|
||||||
# Vertical size of the map (once the nav box and softkey area is removed) is 689px.
|
|
||||||
# 2000nm = 12,152,000ft.
|
|
||||||
RANGES : [{range: 500/6076.12, label: "500ft"},
|
|
||||||
{range: 750/6076.12, label: "750ft"},
|
|
||||||
{range: 1000/6076.12, label: "1000ft"},
|
|
||||||
{range: 1500/6076.12, label: "1500ft"},
|
|
||||||
{range: 2000/6076.12, label: "2000ft"},
|
|
||||||
{range: 0.5, label: "0.5nm"},
|
|
||||||
{range: 0.75, label: "0.75nm"},
|
|
||||||
{range: 1, label: "1nm"},
|
|
||||||
{range: 2, label: "2nm"},
|
|
||||||
{range: 3, label: "3nm"},
|
|
||||||
{range: 4, label: "4nm"},
|
|
||||||
{range: 6, label: "6nm"},
|
|
||||||
{range: 8, label: "8nm"},
|
|
||||||
{range: 10, label: "10nm"},
|
|
||||||
{range: 12, label: "12nm"},
|
|
||||||
{range: 15, label: "15nm"},
|
|
||||||
{range: 20, label: "20nm"},
|
|
||||||
{range: 25, label: "25nm"},
|
|
||||||
{range: 30, label: "30nm"},
|
|
||||||
{range: 40, label: "40nm"},
|
|
||||||
{range: 50, label: "50nm"},
|
|
||||||
{range: 75, label: "75nm"},
|
|
||||||
{range: 100, label: "100nm"},
|
|
||||||
{range: 200, label: "200nm"},
|
|
||||||
{range: 500, label: "500nm"},
|
|
||||||
{range: 1000, label: "1000nm"},
|
|
||||||
{range: 1500, label: "1500nm"},
|
|
||||||
{range: 2000, label: "2000nm"}, ],
|
|
||||||
|
|
||||||
ORIENTATIONS : [
|
|
||||||
{ label: "NORTH UP" },
|
|
||||||
{ label: "TRK UP" },
|
|
||||||
{ label: "DTK UP" },
|
|
||||||
{ label: "HDG UP" },
|
|
||||||
],
|
|
||||||
|
|
||||||
# Layer display configuration:
|
|
||||||
# enabled - whether this layer has been enabled by the user
|
|
||||||
# declutter - the maximum declutter level (0-3) that this layer is visible in
|
|
||||||
# range - the maximum range this layer is visible (configured by user)
|
|
||||||
# max_range - the maximum range value that a user can configure for this layer.
|
|
||||||
LAYER_RANGES : {
|
|
||||||
DTO : { enabled: 0, declutter: 3, range: 2000, max_range: 2000 },
|
|
||||||
|
|
||||||
GRID : { enabled: 0, declutter: 1, range: 20, max_range: 2000 },
|
|
||||||
DME : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
|
||||||
VOR_FG1000 : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
|
||||||
NDB : { enabled: 1, declutter: 1, range: 15, max_range: 30 },
|
|
||||||
FIX : { enabled: 1, declutter: 1, range: 15, max_range: 30 },
|
|
||||||
RTE : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
|
||||||
WPT : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
|
||||||
|
|
||||||
APS : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
|
||||||
FLT : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 },
|
|
||||||
|
|
||||||
WXR : { enabled: 1, declutter: 2, range: 2000, max_range: 2000 },
|
|
||||||
|
|
||||||
APT : { enabled: 1, declutter: 2, range: 150, max_range: 300 },
|
|
||||||
|
|
||||||
TFC : { enabled: 0, declutter: 3, range: 150, max_range: 2000},
|
|
||||||
|
|
||||||
OpenAIP : { enabled: 1, declutter: 1, range: 150, max_range: 300 },
|
|
||||||
STAMEN : { enabled: 1, declutter: 3, range: 500, max_range: 2000 },
|
|
||||||
STAMEN_terrain : { enabled: 1, declutter: 3, range: 500, max_range: 2000 },
|
|
||||||
},
|
|
||||||
|
|
||||||
# TODO: Add STAMEN topo layer, which is visible on all levels as opposed to
|
# TODO: Add STAMEN topo layer, which is visible on all levels as opposed to
|
||||||
# roads, railways, boundaries, cities which are only visible on declutter 0.
|
# roads, railways, boundaries, cities which are only visible on declutter 0.
|
||||||
|
@ -96,7 +28,6 @@ var NavigationMapController =
|
||||||
# Airways levels.
|
# Airways levels.
|
||||||
AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
|
AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
|
||||||
|
|
||||||
|
|
||||||
new : func (page, svg)
|
new : func (page, svg)
|
||||||
{
|
{
|
||||||
var obj = { parents : [ NavigationMapController, MFDPageController.new(page) ] };
|
var obj = { parents : [ NavigationMapController, MFDPageController.new(page) ] };
|
||||||
|
@ -105,7 +36,7 @@ var NavigationMapController =
|
||||||
obj.airways = 0;
|
obj.airways = 0;
|
||||||
obj.page = page;
|
obj.page = page;
|
||||||
obj.setZoom(obj.current_zoom);
|
obj.setZoom(obj.current_zoom);
|
||||||
obj.setOrientation(obj.ORIENTATIONS[0]);
|
obj.setOrientation(fg1000.ORIENTATIONS[0]);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
@ -116,12 +47,12 @@ var NavigationMapController =
|
||||||
me.setZoom(me.current_zoom +1);
|
me.setZoom(me.current_zoom +1);
|
||||||
},
|
},
|
||||||
setZoom : func(zoom) {
|
setZoom : func(zoom) {
|
||||||
if ((zoom < 0) or (zoom > (size(me.RANGES) - 1))) return;
|
if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
|
||||||
me.current_zoom = zoom;
|
me.current_zoom = zoom;
|
||||||
# Ranges above represent vertical ranges, but the display is a rectangle, so
|
# Ranges above represent vertical ranges, but the display is a rectangle, so
|
||||||
# we need to use the diagonal range of the 1024 x 689, which is 617px.
|
# we need to use the diagonal range of the 1024 x 689, which is 617px.
|
||||||
# 617px is 1.8 x 689/2, so we need to increase the range values by x1.8
|
# 617px is 1.8 x 689/2, so we need to increase the range values by x1.8
|
||||||
me.page.setRange(me.RANGES[zoom].range, me.RANGES[zoom].label);
|
me.page.setRange(fg1000.RANGES[zoom].range, fg1000.RANGES[zoom].label);
|
||||||
me.updateVisibility();
|
me.updateVisibility();
|
||||||
},
|
},
|
||||||
setOrientation : func(orientation) {
|
setOrientation : func(orientation) {
|
||||||
|
@ -129,10 +60,10 @@ var NavigationMapController =
|
||||||
},
|
},
|
||||||
updateVisibility : func() {
|
updateVisibility : func() {
|
||||||
# Determine which layers should be visible.
|
# Determine which layers should be visible.
|
||||||
foreach (var layer_name; keys(me.LAYER_RANGES)) {
|
foreach (var layer_name; me.page.mfd.ConfigStore.getLayerNames()) {
|
||||||
var layer = me.LAYER_RANGES[layer_name];
|
var layer = me.page.mfd.ConfigStore.getLayer(layer_name);
|
||||||
if (layer.enabled and
|
if (layer.enabled and
|
||||||
(me.RANGES[me.current_zoom].range <= layer.range) and
|
(fg1000.RANGES[me.current_zoom].range <= layer.range) and
|
||||||
(me.declutter <= layer.declutter) )
|
(me.declutter <= layer.declutter) )
|
||||||
{
|
{
|
||||||
me.page.MFDMap.getLayer(layer_name).setVisible(1);
|
me.page.MFDMap.getLayer(layer_name).setVisible(1);
|
||||||
|
@ -141,15 +72,11 @@ var NavigationMapController =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
configureLayer : func(layer, enabled, range) {
|
|
||||||
me.LAYER_RANGES[layer].enabled = enabled;
|
|
||||||
me.LAYER_RANGES[layer].range = math.min(range, me.LAYER_RANGES[layer].max_range);
|
|
||||||
},
|
|
||||||
isEnabled : func(layer) {
|
isEnabled : func(layer) {
|
||||||
return me.LAYER_RANGES[layer].enabled;
|
return me.page.mfd.ConfigStore.isLayerEnabled(layer);
|
||||||
},
|
},
|
||||||
toggleLayer : func(layer) {
|
toggleLayer : func(layer) {
|
||||||
me.LAYER_RANGES[layer].enabled = ! me.LAYER_RANGES[layer].enabled;
|
me.page.mfd.ConfigStore.toggleLayerEnabled(layer);
|
||||||
me.updateVisibility();
|
me.updateVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -162,6 +89,10 @@ var NavigationMapController =
|
||||||
me.updateVisibility();
|
me.updateVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDCLTRTitle : func() {
|
||||||
|
return me.DCLTR[me.declutter];
|
||||||
|
},
|
||||||
|
|
||||||
# Increment through the AIRWAYS levels. At present this doesn't do anything
|
# Increment through the AIRWAYS levels. At present this doesn't do anything
|
||||||
# except change the label. It should enable/disable different airways
|
# except change the label. It should enable/disable different airways
|
||||||
# information.
|
# information.
|
||||||
|
@ -171,13 +102,16 @@ var NavigationMapController =
|
||||||
device.updateMenus();
|
device.updateMenus();
|
||||||
me.updateVisibility();
|
me.updateVisibility();
|
||||||
},
|
},
|
||||||
|
getAIRWAYSTitle : func() {
|
||||||
|
return me.AIRWAYS[me.airways];
|
||||||
|
},
|
||||||
|
|
||||||
# Set the DTO line target
|
# Set the DTO line target
|
||||||
setDTOLineTarget : func(lat, lon) {
|
setDTOLineTarget : func(lat, lon) {
|
||||||
me.page.MFDMap.getLayer("DTO").controller.setTarget(lat,lon);
|
me.page.MFDMap.getLayer("DTO").controller.setTarget(lat,lon);
|
||||||
},
|
},
|
||||||
enableDTO : func(enable) {
|
enableDTO : func(enable) {
|
||||||
me.LAYER_RANGES["DTO"].enabled = enable;
|
me.page.mfd.ConfigStore.setLayerEnabled("DTO", enable);
|
||||||
me.updateVisibility();
|
me.updateVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,10 @@ var PFDInstruments =
|
||||||
magenta : [1, 0, 1],
|
magenta : [1, 0, 1],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
CDI_SOURCE : [ "GPS", "NAV1", "NAV2" ],
|
||||||
|
|
||||||
|
BRG_SOURCE : ["OFF", "NAV1", "NAV2", "GPS", "ADF"],
|
||||||
|
|
||||||
new : func (mfd, myCanvas, device, svg)
|
new : func (mfd, myCanvas, device, svg)
|
||||||
{
|
{
|
||||||
var obj = {
|
var obj = {
|
||||||
|
@ -38,7 +42,7 @@ var PFDInstruments =
|
||||||
|
|
||||||
_ias_already_exceeded : 0,
|
_ias_already_exceeded : 0,
|
||||||
_windDataDisplay : 0,
|
_windDataDisplay : 0,
|
||||||
_CDISource : "OFF",
|
_CDISource : "GPS",
|
||||||
_BRG1 : "OFF",
|
_BRG1 : "OFF",
|
||||||
_BRG2 : "OFF",
|
_BRG2 : "OFF",
|
||||||
_DME : 0,
|
_DME : 0,
|
||||||
|
@ -46,6 +50,7 @@ var PFDInstruments =
|
||||||
_Map : 0,
|
_Map : 0,
|
||||||
_Multiline : 0,
|
_Multiline : 0,
|
||||||
_annunciation : 0,
|
_annunciation : 0,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Hide various elements for the moment. TODO - implement
|
# Hide various elements for the moment. TODO - implement
|
||||||
|
@ -78,12 +83,17 @@ var PFDInstruments =
|
||||||
obj.device.svg.getElementById("PFDInstruments" ~ id).set("clip", clip);
|
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);
|
||||||
|
|
||||||
#obj.topMenu(device, obj, nil);
|
#obj.topMenu(device, obj, nil);
|
||||||
|
|
||||||
obj.setController(fg1000.PFDInstrumentsController.new(obj, svg));
|
obj.setController(fg1000.PFDInstrumentsController.new(obj, svg));
|
||||||
obj.setWindDisplay(0);
|
obj.setWindDisplay(0);
|
||||||
obj.setCDISource("OFF");
|
obj.setCDISource("GPS");
|
||||||
obj.setBRG1("OFF");
|
obj.setBRG1("OFF");
|
||||||
obj.setBRG2("OFF");
|
obj.setBRG2("OFF");
|
||||||
obj.setDME(0);
|
obj.setDME(0);
|
||||||
|
@ -91,6 +101,10 @@ var PFDInstruments =
|
||||||
obj.setMultiline(0);
|
obj.setMultiline(0);
|
||||||
obj.setAnnunciation(0);
|
obj.setAnnunciation(0);
|
||||||
obj.setOMI("");
|
obj.setOMI("");
|
||||||
|
obj.setInsetMapVisible(0);
|
||||||
|
obj.updateHDG(0);
|
||||||
|
obj.updateSelectedALT(0);
|
||||||
|
obj.updateCRS(0);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
|
@ -99,11 +113,11 @@ var PFDInstruments =
|
||||||
topMenu : func(device, pg, menuitem) {
|
topMenu : func(device, pg, menuitem) {
|
||||||
pg.clearMenu();
|
pg.clearMenu();
|
||||||
pg.resetMenuColors();
|
pg.resetMenuColors();
|
||||||
pg.addMenuItem(1, "INSET", pg); # TODO
|
pg.addMenuItem(1, "INSET", pg, pg.mfd.PFDInstruments.insetMenu);
|
||||||
pg.addMenuItem(3, "PFD", pg, pg.mfd.PFDInstruments.PFDMenu);
|
pg.addMenuItem(3, "PFD", pg, pg.mfd.PFDInstruments.PFDMenu);
|
||||||
pg.addMenuItem(4, "OBS", pg); # TODO
|
pg.addMenuItem(4, "OBS", pg); # TODO
|
||||||
pg.addMenuItem(5, "CDI", pg); # TODO
|
pg.addMenuItem(5, "CDI", pg, pg.incrCDI);
|
||||||
pg.addMenuItem(6, "DME", pg); # TODO
|
#pg.addMenuItem(6, "DME", pg, func(dev, pg, mi) { pg.toggleDME(); } ); # TODO
|
||||||
pg.addMenuItem(7, "XPDR", pg); # TODO
|
pg.addMenuItem(7, "XPDR", pg); # TODO
|
||||||
pg.addMenuItem(8, "IDENT", pg); # TODO
|
pg.addMenuItem(8, "IDENT", pg); # TODO
|
||||||
pg.addMenuItem(9, "TMR/REF", pg); # TODO
|
pg.addMenuItem(9, "TMR/REF", pg); # TODO
|
||||||
|
@ -112,24 +126,121 @@ var PFDInstruments =
|
||||||
device.updateMenus();
|
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 = pg.mfd.PFDInstruments.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
|
||||||
|
},
|
||||||
|
|
||||||
PFDMenu : func(device, pg, menuitem) {
|
PFDMenu : func(device, pg, menuitem) {
|
||||||
pg.clearMenu();
|
pg.clearMenu();
|
||||||
pg.resetMenuColors();
|
pg.resetMenuColors();
|
||||||
pg.addMenuItem(0, "SYN VIS", pg); # TODO
|
pg.addMenuItem(0, "SYN VIS", pg); # TODO
|
||||||
pg.addMenuItem(1, "DFLTS", pg);
|
pg.addMenuItem(1, "DFLTS", pg);
|
||||||
pg.addMenuItem(2, "WIND", pg, pg.mfd.PFDInstruments.windMenu);
|
pg.addMenuItem(2, "WIND", pg, pg.mfd.PFDInstruments.windMenu);
|
||||||
pg.addMenuItem(3, "DME", pg); # TODO
|
#pg.addMenuItem(3, "DME", pg); # TODO
|
||||||
pg.addMenuItem(4, "BRG1", pg); # TODO
|
pg.addMenuItem(4, "BRG1", pg, pg.mfd.PFDInstruments.incrBRG1); # TODO
|
||||||
pg.addMenuItem(5, "HSI FRMT", pg); # TODO
|
pg.addMenuItem(5, "HSI FRMT", pg); # TODO
|
||||||
pg.addMenuItem(6, "BRG2", pg); # TODO
|
pg.addMenuItem(6, "BRG2", pg, pg.mfd.PFDInstruments.incrBRG2); # TODO
|
||||||
#pg.addMenuItem(8, "IDENT", pg); # TODO
|
#pg.addMenuItem(8, "IDENT", pg); # TODO
|
||||||
pg.addMenuItem(8, "ALT UNIT ", pg); # TODO
|
pg.addMenuItem(8, "ALT UNIT ", pg); # TODO
|
||||||
pg.addMenuItem(9, "STD BARO", pg); # TODO
|
pg.addMenuItem(9, "STD BARO", pg, func(dev, pg, mi) { pg.getController().setStdBaro(); } );
|
||||||
pg.addMenuItem(10, "BACK", pg, pg.mfd.PFDInstruments.topMenu);
|
pg.addMenuItem(10, "BACK", pg, pg.mfd.PFDInstruments.topMenu);
|
||||||
pg.addMenuItem(11, "ALERTS", pg); # TODO
|
pg.addMenuItem(11, "ALERTS", pg); # TODO
|
||||||
device.updateMenus();
|
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]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
windMenu : func(device, pg, menuitem) {
|
windMenu : func(device, pg, menuitem) {
|
||||||
pg.clearMenu();
|
pg.clearMenu();
|
||||||
pg.resetMenuColors();
|
pg.resetMenuColors();
|
||||||
|
@ -379,7 +490,7 @@ var PFDInstruments =
|
||||||
updateBARO : func (baro) {
|
updateBARO : func (baro) {
|
||||||
# TODO: Support hPa and inhg
|
# TODO: Support hPa and inhg
|
||||||
#var fmt = me._baro_unit == "inhg" ? "%.2fin" : "%i%shPa";
|
#var fmt = me._baro_unit == "inhg" ? "%.2fin" : "%i%shPa";
|
||||||
var fmt = "%.2fin";
|
var fmt = "%.2fIN";
|
||||||
me.setTextElement("BARO-text", sprintf(fmt, baro));
|
me.setTextElement("BARO-text", sprintf(fmt, baro));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -394,7 +505,6 @@ var PFDInstruments =
|
||||||
},
|
},
|
||||||
|
|
||||||
updateHDG : func (hdg) {
|
updateHDG : func (hdg) {
|
||||||
if (hdg == nil)
|
|
||||||
me.getElement("Heading-bug").setRotation(hdg * D2R);
|
me.getElement("Heading-bug").setRotation(hdg * D2R);
|
||||||
me.setTextElement("SelectedHDG-text", sprintf("%03d°%s", hdg, ""));
|
me.setTextElement("SelectedHDG-text", sprintf("%03d°%s", hdg, ""));
|
||||||
},
|
},
|
||||||
|
@ -459,6 +569,10 @@ var PFDInstruments =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleDME : func() {
|
||||||
|
me.setDME(! me._DME);
|
||||||
|
},
|
||||||
|
|
||||||
setDME : func (enabled) {
|
setDME : func (enabled) {
|
||||||
me._DME = enabled;
|
me._DME = enabled;
|
||||||
me.getElement("DME1").setVisible(enabled);
|
me.getElement("DME1").setVisible(enabled);
|
||||||
|
@ -518,34 +632,48 @@ var PFDInstruments =
|
||||||
me._CDISource = source;
|
me._CDISource = source;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateCDI : func (heading, course, waypoint_valid, course_deviation_deg, deflection_dots, xtrk_nm, from) {
|
updateCDI : func (heading, course, waypoint_valid, course_deviation_deg, deflection_dots, xtrk_nm, from, annun) {
|
||||||
if (me._CDISource == "OFF") return;
|
if (me._CDISource == "OFF") return;
|
||||||
|
|
||||||
var rot = (course - heading) * D2R;
|
if (waypoint_valid == 0) {
|
||||||
me.getElement("CDI")
|
me.getElement(me._CDISource ~ "-CDI").hide();
|
||||||
.setRotation(rot)
|
me.getElement(me._CDISource ~ "-FROM").hide();
|
||||||
.show();
|
me.getElement(me._CDISource ~ "-TO").hide();
|
||||||
me.getElement("GPS-CTI-diamond")
|
me.getElement("CDI").setRotation(0);
|
||||||
.setVisible(waypoint_valid)
|
me.getElement("GPS-CTI-diamond").hide();
|
||||||
.setRotation(course_deviation_deg * D2R);
|
|
||||||
|
|
||||||
if ((me._CDISource == "GPS") and (deflection_dots > 2)) {
|
|
||||||
# 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 %iNM", abs(xtrk_nm)))
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
me.getElement("CDI-GPS-XTK-text").hide();
|
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 (deflection_dots > 2)) {
|
||||||
|
# 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 %iNM", abs(xtrk_nm)))
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
me.getElement("CDI-GPS-XTK-text").hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me._CDISource == "GPS") me.getElement("CDI-GPS-ANN-text").setText(annun).show();
|
||||||
|
|
||||||
|
var scale = math.clamp(deflection_dots, -2.4, 2.4);
|
||||||
|
me.getElement(me._CDISource ~ "-CDI").setTranslation(65 * scale, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
var scale = math.clamp(deflection_dots, -2.4, 2.4);
|
|
||||||
me.getElement(me._CDISource ~ "-CDI").setTranslation(65 * scale, 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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
# Update the wind display. There are three options:
|
# Update the wind display. There are three options:
|
||||||
|
@ -631,5 +759,11 @@ var PFDInstruments =
|
||||||
me.getElement("MarkerText").setText(omi);
|
me.getElement("MarkerText").setText(omi);
|
||||||
}
|
}
|
||||||
me._OMI = omi;
|
me._OMI = omi;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
setInsetMapVisible :func(enabled ) {
|
||||||
|
me.getElement("PFD-Map").setVisible(enabled);
|
||||||
|
me.getElement("PFD-Map-bg").setVisible(enabled);
|
||||||
|
me.insetMap.setVisible(enabled);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,11 +17,6 @@
|
||||||
# PFDInstruments Controller
|
# PFDInstruments Controller
|
||||||
var PFDInstrumentsController =
|
var PFDInstrumentsController =
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
# Declutter levels.
|
|
||||||
WIND : [ "DCLTR", "DCLTR-1", "DCLTR-2", "DCLTR-3"],
|
|
||||||
|
|
||||||
new : func (page, svg)
|
new : func (page, svg)
|
||||||
{
|
{
|
||||||
var obj = {
|
var obj = {
|
||||||
|
@ -35,6 +30,13 @@ var PFDInstrumentsController =
|
||||||
_selected_alt_ft : 0,
|
_selected_alt_ft : 0,
|
||||||
_heading : 0,
|
_heading : 0,
|
||||||
_source : "GPS",
|
_source : "GPS",
|
||||||
|
_from :0,
|
||||||
|
_leg_id : "",
|
||||||
|
_leg_bearing : 0,
|
||||||
|
_leg_distance_nm : 0,
|
||||||
|
_leg_deviation_deg : 0,
|
||||||
|
_deflection_dots :0,
|
||||||
|
_leg_xtrk_nm : 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -74,6 +76,25 @@ var PFDInstrumentsController =
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleRange : func(val)
|
||||||
|
{
|
||||||
|
var incr_or_decr = (val > 0) ? me.page.insetMap.zoomIn() : me.page.insetMap.zoomOut();
|
||||||
|
},
|
||||||
|
|
||||||
|
# Set the STD BARO to 29.92 in Hg
|
||||||
|
setStdBaro : func() {
|
||||||
|
var data = {};
|
||||||
|
data["FMSPressureSettingInHG"] = 29.92;
|
||||||
|
|
||||||
|
var notification = notifications.PFDEventNotification.new(
|
||||||
|
"MFD",
|
||||||
|
me._page.mfd.getDeviceID(),
|
||||||
|
notifications.PFDEventNotification.FMSData,
|
||||||
|
data);
|
||||||
|
|
||||||
|
me.transmitter.NotifyAll(notification);
|
||||||
|
},
|
||||||
|
|
||||||
# Handle update of the airdata information.
|
# Handle update of the airdata information.
|
||||||
# ADC data is produced periodically as an entire set
|
# ADC data is produced periodically as an entire set
|
||||||
handleADCData : func(data) {
|
handleADCData : func(data) {
|
||||||
|
@ -97,6 +118,7 @@ var PFDInstrumentsController =
|
||||||
me.page.updateVSI(data["ADCVerticalSpeedFPM"]);
|
me.page.updateVSI(data["ADCVerticalSpeedFPM"]);
|
||||||
me.page.updateTAS(data["ADCTrueAirspeed"]);
|
me.page.updateTAS(data["ADCTrueAirspeed"]);
|
||||||
me.page.updateBARO(data["ADCPressureSettingInHG"]);
|
me.page.updateBARO(data["ADCPressureSettingInHG"]);
|
||||||
|
|
||||||
me.page.updateOAT(data["ADCOutsideAirTemperatureC"]);
|
me.page.updateOAT(data["ADCOutsideAirTemperatureC"]);
|
||||||
me.page.updateHSI(data["ADCHeadingDeg"]);
|
me.page.updateHSI(data["ADCHeadingDeg"]);
|
||||||
me._heading = data["ADCHeadingDeg"];
|
me._heading = data["ADCHeadingDeg"];
|
||||||
|
@ -113,31 +135,65 @@ var PFDInstrumentsController =
|
||||||
return emesary.Transmitter.ReceiptStatus_OK;
|
return emesary.Transmitter.ReceiptStatus_OK;
|
||||||
},
|
},
|
||||||
|
|
||||||
# Handle update to the FMS information.
|
# Handle update to the FMS information. Note that there is no guarantee
|
||||||
|
# that the entire set of FMS data will be available.
|
||||||
handleFMSData : func(data) {
|
handleFMSData : func(data) {
|
||||||
|
|
||||||
me.page.updateHDG(data["FMSHeadingBug"]);
|
if (data["FMSHeadingBug"] != nil) me.page.updateHDG(data["FMSHeadingBug"]);
|
||||||
me.page.updateSelectedALT(data["FMSSelectedAlt"]);
|
if (data["FMSSelectedAlt"] != nil) {
|
||||||
me._selected_alt_ft = data["FMSSelectedAlt"];
|
me.page.updateSelectedALT(data["FMSSelectedAlt"]);
|
||||||
|
me._selected_alt_ft = data["FMSSelectedAlt"];
|
||||||
me.page.updateCRS(data["FMSLegBearing"]);
|
|
||||||
|
|
||||||
var from = 0;
|
|
||||||
if (me._navSelected == 1) {
|
|
||||||
from = data["FMSNav1From"];
|
|
||||||
} else {
|
|
||||||
from = data["FMSNav2From"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
me.page.updateCDI(
|
if (data["FMSLegValid"] == "false") {
|
||||||
heading: me._heading,
|
# No valid leg data, likely because there's no GPS course set
|
||||||
course: data["FMSLegBearing"],
|
me.page.updateCRS(0);
|
||||||
waypoint_valid: 1,
|
me.page.updateCDI(
|
||||||
course_deviation_deg : data["FMSLegTrackErrorAngle"],
|
heading: me._heading,
|
||||||
deflection_dots : data["FMSLegCourseError"], # TODO: proper conversion depending on source, environment
|
course: 0,
|
||||||
xtrk_nm : data["FMSLegCourseError"],
|
waypoint_valid: 0,
|
||||||
from: from,
|
course_deviation_deg : 0,
|
||||||
);
|
deflection_dots : 0,
|
||||||
|
xtrk_nm : 0,
|
||||||
|
from: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
# Update the bearing indicators with GPS data if that's what we're displaying.
|
||||||
|
if (me.page.getBRG1() == "GPS") me.page.setBRG1("NONE", 0);
|
||||||
|
if (me.page.getBRG2() == "GPS") me.page.setBRG2("NONE", 0);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (data["FMSLegBearing"] != nil) me.page.updateCRS(data["FMSLegBearing"]);
|
||||||
|
|
||||||
|
if (me._navSelected == 1) {
|
||||||
|
if (data["FMSNav1From"] != nil) me._from = data["FMSNav1From"];
|
||||||
|
} else {
|
||||||
|
if (data["FMSNav2From"] != nil) me._from = data["FMSNav2From"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data["FMSLegID"] != nil) me._leg_id = data["FMSLegID"];
|
||||||
|
if (data["FMSLegBearing"] != nil) me._leg_bearing = data["FMSLegBearing"];
|
||||||
|
if (data["FMSLegTrackErrorAngle"] != nil) me._leg_deviation_deg = data["FMSLegTrackErrorAngle"];
|
||||||
|
|
||||||
|
# TODO: Proper cross-track error based on source and flight phase.
|
||||||
|
if (data["FMSLegCourseError"] != nil) me.deflection_dots = data["FMSLegCourseError"];
|
||||||
|
if (data["FMSLegCourseError"] != nil) me._leg_xtrk_nm = data["FMSLegCourseError"];
|
||||||
|
|
||||||
|
me.page.updateCDI(
|
||||||
|
heading: me._heading,
|
||||||
|
course: me._leg_bearing,
|
||||||
|
waypoint_valid: (data["FMSLegValid"] == "true"),
|
||||||
|
course_deviation_deg : me._leg_deviation_deg,
|
||||||
|
deflection_dots : me._deflection_dots,
|
||||||
|
xtrk_nm : me._leg_xtrk_nm,
|
||||||
|
from: me._from,
|
||||||
|
annun: "ENR"
|
||||||
|
);
|
||||||
|
|
||||||
|
# Update the bearing indicators with GPS data if that's what we're displaying.
|
||||||
|
if (me.page.getBRG1() == "GPS") me.page.setBRG1(me._leg_id, me._leg_bearing);
|
||||||
|
if (me.page.getBRG2() == "GPS") me.page.setBRG2(me._leg_id, me._leg_bearing);
|
||||||
|
}
|
||||||
|
|
||||||
return emesary.Transmitter.ReceiptStatus_OK;
|
return emesary.Transmitter.ReceiptStatus_OK;
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,6 +33,9 @@ var SurroundController =
|
||||||
_nav1standby : 0.0,
|
_nav1standby : 0.0,
|
||||||
_nav2active : 0.0,
|
_nav2active : 0.0,
|
||||||
_nav2standby : 0.0,
|
_nav2standby : 0.0,
|
||||||
|
_pressure_settings_inhg : 0.0,
|
||||||
|
_selected_alt_ft : 0.0,
|
||||||
|
_heading_bug_deg : 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.RegisterWithEmesary();
|
obj.RegisterWithEmesary();
|
||||||
|
@ -54,6 +57,17 @@ var SurroundController =
|
||||||
me.transmitter.NotifyAll(notification);
|
me.transmitter.NotifyAll(notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# Helper function to notify the Emesary bridge of a FMSData update.
|
||||||
|
sendFMSDataNotification : func(data) {
|
||||||
|
var notification = notifications.PFDEventNotification.new(
|
||||||
|
"MFD",
|
||||||
|
me._page.mfd.getDeviceID(),
|
||||||
|
notifications.PFDEventNotification.FMSData,
|
||||||
|
data);
|
||||||
|
|
||||||
|
me.transmitter.NotifyAll(notification);
|
||||||
|
},
|
||||||
|
|
||||||
handleNavComData : func(data) {
|
handleNavComData : func(data) {
|
||||||
|
|
||||||
# Store off particularly important data for control.
|
# Store off particularly important data for control.
|
||||||
|
@ -75,6 +89,15 @@ var SurroundController =
|
||||||
return emesary.Transmitter.ReceiptStatus_OK;
|
return emesary.Transmitter.ReceiptStatus_OK;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleFMSADCData : func(data) {
|
||||||
|
if (data["ADCPressureSettingInHG"] != nil) me._pressure_settings_inhg = data["ADCPressureSettingInHG"];
|
||||||
|
if (data["FMSSelectedAlt"] != nil) me._selected_alt_ft = data["FMSSelectedAlt"];
|
||||||
|
if (data["FMSHeadingBug"] != nil) me._heading_bug_deg = data["FMSHeadingBug"];
|
||||||
|
|
||||||
|
# Pass FMS and ADC data straight to the page to display in the header fields
|
||||||
|
me._page.updateHeaderData(data);
|
||||||
|
return emesary.Transmitter.ReceiptStatus_OK;
|
||||||
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
# Handle the various COM and NAV controls at the top left and top right of the Fascia
|
# Handle the various COM and NAV controls at the top left and top right of the Fascia
|
||||||
|
@ -334,6 +357,45 @@ var SurroundController =
|
||||||
handleComVolToggle : func (value) {
|
handleComVolToggle : func (value) {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleBaro : func(value) {
|
||||||
|
var incr_or_decr = (value > 0) ? 1 : -1;
|
||||||
|
var press = me._pressure_settings_inhg + (incr_or_decr * 0.01);
|
||||||
|
var data = {};
|
||||||
|
data["FMSPressureSettingInHG"] = sprintf("%.2f", press);
|
||||||
|
me.sendFMSDataNotification(data);
|
||||||
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAltInner : func(value) {
|
||||||
|
var incr_or_decr = (value > 0) ? 1 : -1;
|
||||||
|
var alt = int(me._selected_alt_ft + incr_or_decr * 100);
|
||||||
|
if (alt < 0) alt = 0;
|
||||||
|
var data = {};
|
||||||
|
data["FMSSelectedAlt"] = alt;
|
||||||
|
me.sendFMSDataNotification(data);
|
||||||
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleAltOuter : func(value) {
|
||||||
|
var incr_or_decr = (value > 0) ? 1 : -1;
|
||||||
|
var alt = int(me._selected_alt_ft + incr_or_decr * 1000);
|
||||||
|
if (alt < 0) alt = 0;
|
||||||
|
var data = {};
|
||||||
|
data["FMSSelectedAlt"] = alt;
|
||||||
|
me.sendFMSDataNotification(data);
|
||||||
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
||||||
|
},
|
||||||
|
|
||||||
|
handleHeading : func(value) {
|
||||||
|
var incr_or_decr = (value > 0) ? 1 : -1;
|
||||||
|
var hdg = me._heading_bug_deg + incr_or_decr;
|
||||||
|
hdg = math.mod(hdg, 360);
|
||||||
|
var data = {};
|
||||||
|
data["FMSHeadingBug"] = sprintf("%i", hdg);
|
||||||
|
me.sendFMSDataNotification(data);
|
||||||
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
||||||
|
},
|
||||||
|
|
||||||
# These methods are slightly unusual in that they are called by other
|
# These methods are slightly unusual in that they are called by other
|
||||||
# controllers when the CRSR is not active. Hence they aren't referenced
|
# controllers when the CRSR is not active. Hence they aren't referenced
|
||||||
# in the RegisterWithEmesary call below.
|
# in the RegisterWithEmesary call below.
|
||||||
|
@ -381,10 +443,8 @@ var SurroundController =
|
||||||
(notification.Event_Id == notifications.PFDEventNotification.ADCData) )
|
(notification.Event_Id == notifications.PFDEventNotification.ADCData) )
|
||||||
and notification.EventParameter != nil)
|
and notification.EventParameter != nil)
|
||||||
{
|
{
|
||||||
# Pass FMS and ADC data straight to the page to display in the header fields
|
return controller.handleFMSADCData(notification.EventParameter);
|
||||||
return controller._page.updateHeaderData(notification.EventParameter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
return emesary.Transmitter.ReceiptStatus_NotProcessed;
|
||||||
};
|
};
|
||||||
|
|
239
Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
Normal file
239
Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
# Copyright 2018 Stuart Buchanan
|
||||||
|
# This file is part of FlightGear.
|
||||||
|
#
|
||||||
|
# FlightGear 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/>.
|
||||||
|
#
|
||||||
|
# Common Navigation map functions
|
||||||
|
var NavMap = {
|
||||||
|
|
||||||
|
# Declutter levels.
|
||||||
|
DCLTR : [ "DCLTR", "DCLTR-1", "DCLTR-2", "DCLTR-3"],
|
||||||
|
|
||||||
|
# Airways levels.
|
||||||
|
AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
|
||||||
|
|
||||||
|
new : func(page, element, center, clip="", zindex=0, vis_shift=0 )
|
||||||
|
{
|
||||||
|
var obj = {
|
||||||
|
parents : [ NavMap ],
|
||||||
|
_group : page.getGroup(),
|
||||||
|
_svg : page.getSVG(),
|
||||||
|
_page : page,
|
||||||
|
_pageName : page.getPageName(),
|
||||||
|
current_zoom : 13,
|
||||||
|
declutter : 0,
|
||||||
|
airways : 0,
|
||||||
|
vis_shift : vis_shift,
|
||||||
|
};
|
||||||
|
|
||||||
|
element.setTranslation(center[0], center[1]);
|
||||||
|
|
||||||
|
obj.Styles = fg1000.NavigationMapStyles.new();
|
||||||
|
obj.Options = fg1000.NavigationMapOptions.new();
|
||||||
|
|
||||||
|
obj.Map = element.createChild("map");
|
||||||
|
obj.Map.setScreenRange(689/2.0);
|
||||||
|
|
||||||
|
obj._rangeDisplay = obj._svg.getElementById(obj._pageName ~ "RangeDisplay");
|
||||||
|
if (obj._rangeDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "RangeDisplay");
|
||||||
|
|
||||||
|
obj._orientationDisplay = obj._svg.getElementById(obj._pageName ~ "OrientationDisplay");
|
||||||
|
if (obj._orientationDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "OrientationDisplay");
|
||||||
|
|
||||||
|
# Initialize the controllers:
|
||||||
|
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
|
||||||
|
var source = ctrl_ns.SOURCES["current-pos"];
|
||||||
|
if (source == nil) {
|
||||||
|
# TODO: amend
|
||||||
|
var source = ctrl_ns.SOURCES["current-pos"] = {
|
||||||
|
getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),
|
||||||
|
getAltitude: func getprop('/position/altitude-ft'),
|
||||||
|
getHeading: func {
|
||||||
|
if (me.aircraft_heading)
|
||||||
|
getprop('/orientation/heading-deg')
|
||||||
|
else 0
|
||||||
|
},
|
||||||
|
aircraft_heading: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n) {
|
||||||
|
source.aircraft_heading = n.getBoolValue();
|
||||||
|
}, 1);
|
||||||
|
# Make it move with our aircraft:
|
||||||
|
obj.Map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
|
||||||
|
|
||||||
|
if (clip != "") {
|
||||||
|
obj.Map.set("clip-frame", canvas.Element.LOCAL);
|
||||||
|
obj.Map.set("clip", clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zindex != 0) {
|
||||||
|
element.setInt("z-index", zindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = func(name,vis=1,zindex=nil) return caller(0)[0];
|
||||||
|
# TODO: we'll need some z-indexing here, right now it's just random
|
||||||
|
foreach(var type; [r('GRID'),r('DTO',0),r('TFC',0),r('APT'),r('DME'),r('VOR_FG1000'),r('NDB'),r('FIX',0),r('GPS'),r('RTE'),r('WPT'),r('FLT'),r('WXR',0),r('APS')] ) {
|
||||||
|
obj.Map.addLayer(
|
||||||
|
factory: canvas.SymbolLayer,
|
||||||
|
type_arg: type.name,
|
||||||
|
priority: 4,
|
||||||
|
style: obj.Styles.getStyle(type.name),
|
||||||
|
options: obj.Options.getOption(type.name),
|
||||||
|
visible: type.vis);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var type; [ r('STAMEN_terrain'),r('STAMEN'), r('OpenAIP') ]) {
|
||||||
|
obj.Map.addLayer(
|
||||||
|
factory: canvas.OverlayLayer,
|
||||||
|
type_arg: type.name,
|
||||||
|
priority: 1,
|
||||||
|
style: obj.Styles.getStyle(type.name),
|
||||||
|
options: obj.Options.getOption(type.name),
|
||||||
|
visible: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.setZoom(obj.current_zoom);
|
||||||
|
obj.setOrientation(0);
|
||||||
|
obj.Map.setVisible(0);
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleLayerVisible : func(name) {
|
||||||
|
(var l = me.Map.getLayer(name)).setVisible(l.getVisible());
|
||||||
|
},
|
||||||
|
|
||||||
|
setLayerVisible : func(name,n=1) {
|
||||||
|
me.Map.getLayer(name).setVisible(n);
|
||||||
|
},
|
||||||
|
|
||||||
|
setRange : func(range, label) {
|
||||||
|
me.Map.setRange(range);
|
||||||
|
me._rangeDisplay.setText(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
setOrientation : func(orientation) {
|
||||||
|
# TODO - implment this
|
||||||
|
me._orientationDisplay.setText(fg1000.ORIENTATIONS[orientation].label);
|
||||||
|
},
|
||||||
|
|
||||||
|
setScreenRange : func(range) {
|
||||||
|
me.Map.setScreenRange(range);
|
||||||
|
},
|
||||||
|
|
||||||
|
zoomIn : func() {
|
||||||
|
me.setZoom(me.current_zoom -1);
|
||||||
|
},
|
||||||
|
|
||||||
|
zoomOut : func() {
|
||||||
|
me.setZoom(me.current_zoom +1);
|
||||||
|
},
|
||||||
|
|
||||||
|
setZoom : func(zoom) {
|
||||||
|
if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
|
||||||
|
me.current_zoom = zoom;
|
||||||
|
# Ranges above represent vertical ranges, but the display is a rectangle, so
|
||||||
|
# we need to use the diagonal range of the 1024 x 689, which is 617px.
|
||||||
|
# 617px is 1.8 x 689/2, so we need to increase the range values by x1.8
|
||||||
|
me.setRange(fg1000.RANGES[zoom].range, fg1000.RANGES[zoom].label);
|
||||||
|
me.updateVisibility();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateVisibility : func() {
|
||||||
|
# Determine which layers should be visible.
|
||||||
|
foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
|
||||||
|
var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
|
||||||
|
|
||||||
|
# Layers are only displayed if:
|
||||||
|
# 1) the user has enabled them.
|
||||||
|
# 2) The current zoom level is _less_ than the maximum range for the layer
|
||||||
|
# (i.e. as the range gets larger, we remove layers). Note that for
|
||||||
|
# inset maps, the range that items are removed is lower.
|
||||||
|
# 3) They haven't been removed due to the declutter level.
|
||||||
|
var effective_zoom = math.clamp(me.current_zoom + me.vis_shift, 0, size(fg1000.RANGES));
|
||||||
|
var effective_range = fg1000.RANGES[effective_zoom].range;
|
||||||
|
if (layer.enabled and
|
||||||
|
(effective_range <= layer.range) and
|
||||||
|
(me.declutter <= layer.declutter) )
|
||||||
|
{
|
||||||
|
me.Map.getLayer(layer_name).setVisible(1);
|
||||||
|
} else {
|
||||||
|
me.Map.getLayer(layer_name).setVisible(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isEnabled : func(layer) {
|
||||||
|
return me._page.mfd.ConfigStore.isLayerEnabled(layer);
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleLayer : func(layer) {
|
||||||
|
me._page.mfd.ConfigStore.toggleLayerEnabled(layer);
|
||||||
|
me.updateVisibility();
|
||||||
|
},
|
||||||
|
|
||||||
|
# Increment through the de-clutter levels, which impact what layers are
|
||||||
|
# displayed. We also need to update the declutter menu item.
|
||||||
|
incrDCLTR : func(device, menuItem) {
|
||||||
|
me.declutter = math.mod(me.declutter +1, 4);
|
||||||
|
me.updateVisibility();
|
||||||
|
return me.DCLTR[me.declutter];
|
||||||
|
},
|
||||||
|
|
||||||
|
getDCLTRTitle : func() {
|
||||||
|
return me.DCLTR[me.declutter];
|
||||||
|
},
|
||||||
|
|
||||||
|
# Increment through the AIRWAYS levels. At present this doesn't do anything
|
||||||
|
# except change the label. It should enable/disable different airways
|
||||||
|
# information.
|
||||||
|
incrAIRWAYS : func(device, menuItem) {
|
||||||
|
me.airways = math.mod(me.airways +1, 4);
|
||||||
|
me.updateVisibility();
|
||||||
|
return me.AIRWAYS[me.airways];
|
||||||
|
},
|
||||||
|
|
||||||
|
getAIRWAYSTitle : func() {
|
||||||
|
return me.AIRWAYS[me.airways];
|
||||||
|
},
|
||||||
|
|
||||||
|
# Set the DTO line target
|
||||||
|
setDTOLineTarget : func(lat, lon) {
|
||||||
|
me.Map.getLayer("DTO").controller.setTarget(lat,lon);
|
||||||
|
},
|
||||||
|
enableDTO : func(enable) {
|
||||||
|
me._page.mfd.ConfigStore.setLayerEnabled("DTO", enable);
|
||||||
|
me.updateVisibility();
|
||||||
|
},
|
||||||
|
|
||||||
|
handleRange : func(val)
|
||||||
|
{
|
||||||
|
var incr_or_decr = (val > 0) ? 1 : -1;
|
||||||
|
me.setZoom(me.current_zoom + incr_or_decr);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMap : func() {
|
||||||
|
return me.Map;
|
||||||
|
},
|
||||||
|
show : func() {
|
||||||
|
me.Map.show();
|
||||||
|
},
|
||||||
|
hide : func() {
|
||||||
|
me.Map.hide();
|
||||||
|
},
|
||||||
|
setVisible : func(visible) {
|
||||||
|
me.Map.setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
Loading…
Reference in a new issue