1
0
Fork 0

Add Config Store and MFD Header display.

ConfigStore for storing and retrieving config settings (needs XML import/export)
Header display with 4 different header fields (all configurable)
Publisher for ADC and FMS.
This commit is contained in:
Stuart Buchanan 2018-01-18 19:37:50 +00:00
parent e0f721450a
commit 0c4544c1e1
11 changed files with 324 additions and 91 deletions

View file

@ -23,11 +23,11 @@
borderopacity="0" borderopacity="0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="1.4142135" inkscape:zoom="2.828427"
inkscape:cx="208.90255" inkscape:cx="445.86013"
inkscape:cy="491.35422" inkscape:cy="589.65442"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="SurroundGroup" inkscape:current-layer="MFD-navbox"
showgrid="true" showgrid="true"
inkscape:window-width="2495" inkscape:window-width="2495"
inkscape:window-height="1416" inkscape:window-height="1416"
@ -450,73 +450,6 @@
id="path4370" id="path4370"
inkscape:connector-curvature="0" /> inkscape:connector-curvature="0" />
</g> </g>
<g
style="display:inline"
inkscape:label="PFD-navbox"
id="PFD-navbox">
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="263.75085"
y="22.123667"
id="LEG-text"
inkscape:label="LEG-text"><tspan
sodipodi:role="line"
id="tspan4549"
x="263.75085"
y="22.123667"
style="fill:#ff00ff" /></text>
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="500.63165"
y="21.821583"
id="DIS"
inkscape:label="DIS"><tspan
sodipodi:role="line"
id="tspan4553"
x="500.63165"
y="21.821583">DIS</tspan></text>
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:26.66666603px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="540.22955"
y="21.746063"
id="DIS-text"
inkscape:label="DIS-text"><tspan
sodipodi:role="line"
id="tspan4557"
x="540.22955"
y="21.746063">--.-</tspan></text>
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="639.22455"
y="22.123667"
id="ETE"
inkscape:label="ETE"><tspan
sodipodi:role="line"
id="tspan4561"
x="639.22455"
y="22.123667">ETE</tspan></text>
<text
sodipodi:linespacing="125%"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:26.66666603px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="681.65094"
y="21.746063"
id="ETE-text"
inkscape:label="ETE-text"><tspan
sodipodi:role="line"
id="tspan4569"
x="681.65094"
y="21.746063"
style="fill:#ff00ff">--:--</tspan></text>
</g>
<g <g
style="display:inline" style="display:inline"
inkscape:label="MFD-navbox" inkscape:label="MFD-navbox"
@ -527,7 +460,7 @@
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="265.87216" x="265.87216"
y="22.002344" y="22.002344"
id="DATA-FIELD1-ID-text" id="SurroundHeader1Label"
inkscape:label="DATA-FIELD1-ID-text"><tspan inkscape:label="DATA-FIELD1-ID-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4587" id="tspan4587"
@ -539,39 +472,39 @@
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="389.5159" x="389.5159"
y="22.002344" y="22.01276"
id="DATA-FIELD2-ID-text" id="SurroundHeader2Label"
inkscape:label="DATA-FIELD2-ID-text"><tspan inkscape:label="DATA-FIELD2-ID-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4587-6" id="tspan4587-6"
x="389.5159" x="389.5159"
y="22.002344" y="22.01276"
style="fill:#ffffff">DTK</tspan></text> style="fill:#ffffff">DTK</tspan></text>
<text <text
sodipodi:linespacing="125%" sodipodi:linespacing="125%"
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="513.15961" x="513.15961"
y="22.002344" y="22.01276"
id="DATA-FIELD3-ID-text" id="SurroundHeader3Label"
inkscape:label="DATA-FIELD3-ID-text"><tspan inkscape:label="DATA-FIELD3-ID-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4587-5" id="tspan4587-5"
x="513.15961" x="513.15961"
y="22.002344" y="22.01276"
style="fill:#ffffff">TRK</tspan></text> style="fill:#ffffff">TRK</tspan></text>
<text <text
sodipodi:linespacing="125%" sodipodi:linespacing="125%"
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="636.80328" x="636.80328"
y="22.002344" y="22.01276"
id="DATA-FIELD4-ID-text" id="SurroundHeader4Label"
inkscape:label="DATA-FIELD4-ID-text"><tspan inkscape:label="DATA-FIELD4-ID-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4587-62" id="tspan4587-62"
x="636.80328" x="636.80328"
y="22.002344" y="22.01276"
style="fill:#ffffff">ETE</tspan></text> style="fill:#ffffff">ETE</tspan></text>
<text <text
sodipodi:linespacing="125%" sodipodi:linespacing="125%"
@ -579,7 +512,7 @@
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="313.06903" x="313.06903"
y="22.002344" y="22.002344"
id="DATA-FIELD1-VAL-text" id="SurroundHeader1Value"
inkscape:label="DATA-FIELD1-VAL-text"><tspan inkscape:label="DATA-FIELD1-VAL-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4625" id="tspan4625"
@ -591,7 +524,7 @@
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="436.71277" x="436.71277"
y="22.002344" y="22.002344"
id="DATA-FIELD2-VAL-text" id="SurroundHeader2Value"
inkscape:label="DATA-FIELD2-VAL-text"><tspan inkscape:label="DATA-FIELD2-VAL-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4625-1" id="tspan4625-1"
@ -603,7 +536,7 @@
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="560.35645" x="560.35645"
y="22.002344" y="22.002344"
id="DATA-FIELD3-VAL-text" id="SurroundHeader3Value"
inkscape:label="DATA-FIELD3-VAL-text"><tspan inkscape:label="DATA-FIELD3-VAL-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4625-7" id="tspan4625-7"
@ -614,13 +547,13 @@
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="font-style:normal;font-weight:normal;font-size:21.33333397px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="684.00012" x="684.00012"
y="22.002344" y="19.752344"
id="DATA-FIELD4-VAL-text" id="SurroundHeader4Value"
inkscape:label="DATA-FIELD4-VAL-text"><tspan inkscape:label="DATA-FIELD4-VAL-text"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan4625-2" id="tspan4625-2"
x="684.00012" x="684.00012"
y="22.002344">--:--</tspan></text> y="19.752344">--:--</tspan></text>
</g> </g>
<rect <rect
y="743.99951" y="743.99951"

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View file

@ -165,7 +165,6 @@ var AirportInfoController =
me.page.mfd.SurroundController.setStandbyNavComFreq(me.page.freqSelect.getValue()); me.page.mfd.SurroundController.setStandbyNavComFreq(me.page.freqSelect.getValue());
} }
return emesary.Transmitter.ReceiptStatus_Finished; return emesary.Transmitter.ReceiptStatus_Finished;
} else { } else {
return emesary.Transmitter.ReceiptStatus_NotProcessed; return emesary.Transmitter.ReceiptStatus_NotProcessed;

View file

@ -0,0 +1,110 @@
# Copyright (C) 2018 Stuart Buchanan
# FG1000 Configuration store
#
# This only stores configuration with pre-defined values
#
var ConfigStore = {
configValues : {
"DisplayUnitsNavAngle": ["MAGNETIC", "TRUE"] ,
"DisplayUnitsDistanceAndSpeed": ["NAUTICAL", "METRIC"] ,
"DisplayUnitsAltitude": ["FEET", "METERS"] ,
"DisplayUnitsTemperature": ["CELCIUS", "FAHRENHEIT"] ,
"BaroTransitionAlert": ["ON", "OFF"] ,
"BaroTransitionAltitude": ["6000", "18000"] ,
"AirspaceAlertBuffer": ["100", "200", "300", "400", "500", "750", "1000"] ,
"AirspaceAlertClassB": ["OFF", "ON"] ,
"AirspaceAlertClassC": ["OFF", "ON"] ,
"AirspaceAlertClassD": ["OFF", "ON"] ,
"AirspaceAlertRestricted": ["OFF", "ON"] ,
"AirspaceAlertMOA": ["OFF", "ON"] ,
"AirspaceAlertOther": ["OFF", "ON"] ,
"ArrivalAlert": ["OFF", "ON"] ,
"ArrivalDistance": ["0.0", "1.0", "2.0", "3.0", "4.0", "6.0", "8.0", "10.0"] ,
"AudioAlertVoice": ["MALE", "FEMALE"] ,
"PageNavigationChangeOnFirstClick": ["OFF", "ON"] ,
"PageNavigationTimeout" : [0.5, 1.0, 2.0, 3.0] ,
# MFD Header Fields
#
# Bearing (BRG)
# Crosstrack Error (XTK)
# Distance (DIS)
# Desired Track (DTK)
# Endurance (END)
# En Route Safe Altitude (ESA)
# Estimated Time of Arrival (ETA)
# Estimated Time En Route (ETE)
# Fuel Over Destination (FOD)
# Fuel On Board (FOB)
# Ground Speed (GS)
# Minimum Safe Altitude (MSA)
# True Air Speed (TAS)
# Track Angle Error (TKE)
# Track (TRK)
# Vertical Speed Required (VSR)
"MFDHeader1": ["BRG", "XTK", "DIS", "DTK", "END", "ESA", "ETA", "ETE", "FOD", "FOB", "GS", "MSA", "TAS", "TKE", "TRK", "VSR"] ,
"MFDHeader2": ["BRG", "XTK", "DIS", "DTK", "END", "ESA", "ETA", "ETE", "FOD", "FOB", "GS", "MSA", "TAS", "TKE", "TRK", "VSR"] ,
"MFDHeader3": ["BRG", "XTK", "DIS", "DTK", "END", "ESA", "ETA", "ETE", "FOD", "FOB", "GS", "MSA", "TAS", "TKE", "TRK", "VSR"] ,
"MFDHeader4": ["BRG", "XTK", "DIS", "DTK", "END", "ESA", "ETA", "ETE", "FOD", "FOB", "GS", "MSA", "TAS", "TKE", "TRK", "VSR"] ,
},
new : func()
{
var obj ={
parents : [ ConfigStore ],
_values : {},
};
foreach (var i; keys(ConfigStore.configValues)) {
var values = ConfigStore.configValues[i];
obj.set(i, values[0]);
}
# Special case defaults
obj.set("MFDHeader1", "GS");
obj.set("MFDHeader2", "DIS");
obj.set("MFDHeader3", "ETE");
# ESA should be the default, but it's not implemented right now, so use FOD
#obj.set("MFDHeader4", "ESA");
obj.set("MFDHeader4", "FOD");
return obj;
},
set : func(name, value) {
# Validate name is something we know.
assert(contains(ConfigStore.configValues, name), "ConfigStore does not contain name " ~ name);
if (size(ConfigStore.configValues[name]) == 0) {
# If not valid values, then anything goes.
me._values[name] = value;
} else {
# Validate the value is part of the set of acceptable values
var found = 0;
foreach(var val; ConfigStore.configValues[name]) {
if (value == val) {
found =1;
break;
}
}
assert(found == 1,
"Invalid value for " ~ name ~ ": " ~ value ~
"(Should be one of " ~ string.join(", ", ConfigStore.configValues[name]) ~ ")");
me._values[name] = value;
}
},
get : func(name) {
return me._values[name];
},
};

View file

@ -0,0 +1,28 @@
# Air Data Computer Driver using Emesary to publish data such as
#
# Airspeed
# Orientation
# Rate of turn
# Heading
# Air Temperature
#
#
# For the moment these are just taken directly from the raw properties. They
# should probably come from aircraft-specific instrumentation.
var GenericADCPublisher =
{
new : func (frequency=0.5) {
var obj = {
parents : [
GenericADCPublisher,
PeriodicPropertyPublisher.new(notifications.PFDEventNotification.ADCData, frequency)
],
};
obj.addPropMap("ADCTrueAirspeed", "/instrumentation/airspeed-indicator/true-speed-kt");
return obj;
},
};

View file

@ -30,7 +30,6 @@ var GenericEISPublisher =
# Custom publish method as we package the values into an array of engines, # Custom publish method as we package the values into an array of engines,
# in this case, only one! # in this case, only one!
publish : func() { publish : func() {
var engineData0 = {}; var engineData0 = {};

View file

@ -0,0 +1,73 @@
# FMS Driver using Emesary to publish data from the inbuilt FMS properties
var GenericFMSPublisher =
{
new : func (frequency=0.5) {
var obj = {
parents : [
GenericFMSPublisher,
PeriodicPropertyPublisher.new(notifications.PFDEventNotification.FMSData, frequency)
],
};
obj.addPropMap("FMSLegBearing", "/instrumentation/gps/wp/wp[1]/bearing-mag-deg");
obj.addPropMap("FMSLegCourseError", "/instrumentation/gps/wp/wp[1]/course-error-nm");
obj.addPropMap("FMSLegDesiredTrack", "/instrumentation/gps/indicated-track-magnetic-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");
return obj;
},
# Custom publish method as we need to calculate some particular values manually.
publish : func() {
var gpsdata = {};
foreach (var propmap; me._propmaps) {
var name = propmap.getName();
gpsdata[name] = propmap.getValue();
}
# 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;
total_fuel = total_fuel + (getprop("/consumables/fuel/tank[1]/indicated-level-gal_us") or 0.0);
var fuel_flow = getprop("/engines/engine[0]/fuel-flow-gph") or 1.0;
gpsdata["FuelOnBoard"] = total_fuel;
gpsdata["EnduranceHrs"] = total_fuel / fuel_flow;
var plan = flightplan();
var dst = 0.0;
if (plan.getPlanSize() > 0) {
# Determine the distance to travel, based on
# - current distance to the next WP,
# - length of each subsequent leg.
dst = getprop("/instrumentation/gps/wp/wp[1]/distance-nm") or 0.0;
if (plan.indexOfWP(plan.currentWP()) < (plan.getPlanSize() -1)) {
for(var i=plan.indexOfWP(plan.currentWP()) + 1; i < plan.getPlanSize(); i = i+1) {
var leg = plan.getWP(i);
if (leg != nil ) dst = dst + leg.leg_distance;
}
}
}
gpsdata["FMSDistance"] = dst;
var spd = getprop("/instrumentation/gps/indicated-ground-speed-kt") or 1.0;
var time_hrs = dst / spd;
gpsdata["FMSEstimatedTimeEnroute"] = time_hrs;
gpsdata["FMSFuelOverDestination"] = total_fuel - time_hrs * fuel_flow;
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
gpsdata);
me._transmitter.NotifyAll(notification);
},
};

View file

@ -8,6 +8,8 @@ io.include("constants.nas");
var nasal_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/FG1000/Nasal/"; var nasal_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/FG1000/Nasal/";
io.load_nasal(nasal_dir ~ '/ConfigStore.nas', "fg1000");
io.load_nasal(nasal_dir ~ '/MFDPage.nas', "fg1000"); io.load_nasal(nasal_dir ~ '/MFDPage.nas', "fg1000");
io.load_nasal(nasal_dir ~ '/MFDPageController.nas', "fg1000"); io.load_nasal(nasal_dir ~ '/MFDPageController.nas', "fg1000");
@ -71,6 +73,8 @@ var MFD =
Surround : nil, Surround : nil,
}; };
obj.ConfigStore = fg1000.ConfigStore.new();
obj._svg = myCanvas.createGroup("softkeys"); obj._svg = myCanvas.createGroup("softkeys");
obj._svg.set("clip-frame", canvas.Element.LOCAL); obj._svg.set("clip-frame", canvas.Element.LOCAL);
obj._svg.set("clip", "rect(0px, 1024px, 768px, 0px)"); obj._svg.set("clip", "rect(0px, 1024px, 768px, 0px)");

View file

@ -38,6 +38,27 @@ var PAGE_GROUPS = [
} }
]; ];
# Mapping for header labels to specific FMS or ADC messages, and sprintf formatting
# to use
var HEADER_MAPPING = {
"BRG" : { message : "FMSLegBearing", format : "%d"},
"XTK" : { message : "FMSLegCourseError", format : "%.1fnm"},
"DIS" : { message : "FMSDistance", format : "%.1fnm"},
"DTK" : { message : "FMSLegDesiredTrack", format : "%d"},
"END" : { message : "EnduranceHrs", format : "%.1fhrs"},
"ESA" : { message : "EnRouteSafeAltitude", format : "%dft"}, # TODO
"ETA" : { message : "FMSEstimatedTimeArrival", format : ""}, # TODO
"ETE" : { message : "FMSEstimatedTimeEnroute", format : ""},
"FOD" : { message : "FMSFuelOverDestination", format : "%dgal"},
"FOB" : { message : "FuelOnBoard", format : "%dgal"},
"GS" : { message : "FMSGroundspeed", format : "%dkts"},
"MSA" : { message : "MinimumSafeAltitude", format : "%dft"}, # TODO
"TAS" : { message : "ADCTrueAirspeed", format : "%dkts"},
"TKE" : { message : "FMSLegTrackErrorAngle", format : "%d"},
"TRK" : { message : "FMSLegTrack", format : "%d"},
"VSR" : { message : "FMSLegVerticalSpeedRequired", format : "%dfpm"}, # TODO
};
var Surround = var Surround =
{ {
new : func (mfd, myCanvas, device, svg) new : func (mfd, myCanvas, device, svg)
@ -52,7 +73,11 @@ var Surround =
"Comm2StandbyFreq", "Comm2SelectedFreq", "Comm2StandbyFreq", "Comm2SelectedFreq",
"Nav1StandbyFreq", "Nav1SelectedFreq", "Nav1StandbyFreq", "Nav1SelectedFreq",
"Nav2StandbyFreq", "Nav2SelectedFreq", "Nav2StandbyFreq", "Nav2SelectedFreq",
"Nav1ID", "Nav2ID" "Nav1ID", "Nav2ID",
"Header1Label", "Header1Value",
"Header2Label", "Header2Value",
"Header3Label", "Header3Value",
"Header4Label", "Header4Value",
]; ];
obj.addTextElements(textElements); obj.addTextElements(textElements);
@ -181,6 +206,41 @@ var Surround =
} }
}, },
# Update Header data with FMS or ADC data.
updateHeaderData : func(data) {
var headers = ["Header1", "Header2", "Header3", "Header4"];
foreach (var header; headers) {
# Get the currently configured heading and set the surround to display it.
var label = me.mfd.ConfigStore.get("MFD" ~ header);
assert(label != nil, "No header configured in ConfigStore for " ~ header);
me.setTextElement(header ~ "Label", label);
# Determine how it maps to Emesary data notifications
var mapping = HEADER_MAPPING[label];
assert(mapping != nil, "No header mapping for " ~ label);
if (data[mapping.message] != nil) {
# Format and display the value
var value = sprintf(mapping.format, data[mapping.message]);
if (mapping.message == "FMSEstimatedTimeEnroute") {
# Special case to format time strings.
var hrs = int(data[mapping.message]);
var mins = int(60*(data[mapping.message] - hrs));
var secs = int(3600*(data[mapping.message] - hrs - mins/60));
if (hrs == 0) {
value = sprintf("%d:%02d", mins, secs);
} else {
value = sprintf("%d:%02d", hrs, mins);
}
}
me.setTextElement(header ~ "Value", value);
}
}
},
addPage : func(name, page) addPage : func(name, page)
{ {
me._pageList[name] = page; me._pageList[name] = page;

View file

@ -359,11 +359,21 @@ var SurroundController =
{ {
if (notification.Device_Id == pfd_obj.device_id if (notification.Device_Id == pfd_obj.device_id
and notification.NotificationType == notifications.PFDEventNotification.DefaultType) { and notification.NotificationType == notifications.PFDEventNotification.DefaultType) {
if (notification.Event_Id == notifications.PFDEventNotification.NavComData if (notification.Event_Id == notifications.PFDEventNotification.NavComData
and notification.EventParameter != nil) and notification.EventParameter != nil)
{ {
return controller.handleNavComData(notification.EventParameter); return controller.handleNavComData(notification.EventParameter);
} }
if (((notification.Event_Id == notifications.PFDEventNotification.FMSData) or
(notification.Event_Id == notifications.PFDEventNotification.ADCData) )
and notification.EventParameter != nil)
{
# Pass FMS and ADC data straight to the page to display in the header fields
return controller._page.updateHeaderData(notification.EventParameter);
}
} }
return emesary.Transmitter.ReceiptStatus_NotProcessed; return emesary.Transmitter.ReceiptStatus_NotProcessed;
}; };

View file

@ -110,6 +110,9 @@ var MFDGUI =
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/GenericADCPublisher.nas', "fg1000");
# Now create the MFD itself # Now create the MFD itself
if (obj.scale > 0.999) { if (obj.scale > 0.999) {
# If we're at full scale, then create it directly in this Canvas as that # If we're at full scale, then create it directly in this Canvas as that
@ -154,6 +157,12 @@ var MFDGUI =
obj.navdataInterface = fg1000.NavDataInterface.new(obj.mfd.getDevice()); obj.navdataInterface = fg1000.NavDataInterface.new(obj.mfd.getDevice());
obj.navdataInterface.start(); obj.navdataInterface.start();
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
obj.gpsPublisher.start();
obj.adcPublisher = fg1000.GenericADCPublisher.new();
obj.adcPublisher.start();
# Add a event listener for the mouse wheel, which is used for turning the # Add a event listener for the mouse wheel, which is used for turning the
# knobs. # knobs.
obj.myCanvas.addEventListener("wheel", func(e) obj.myCanvas.addEventListener("wheel", func(e)
@ -231,6 +240,12 @@ var MFDGUI =
me.navdataInterface.stop(); me.navdataInterface.stop();
me.navdataInterface =nil; me.navdataInterface =nil;
me.gpsPublisher.stop();
me.gpsPublisher = nil;
me.adcPublisher.stop();
me.adcPublisher = nil;
# Clean up the window itself # Clean up the window itself
call(canvas.Window.del, [], me.window); call(canvas.Window.del, [], me.window);
}, },

View file

@ -554,7 +554,9 @@ var PFDEventNotification =
HardKeyPushed : 4, #event parameter contains single { Id: , Value: } tuple HardKeyPushed : 4, #event parameter contains single { Id: , Value: } tuple
EngineData : 5, #event parameter contains an array of hashes, each containing information about a given engine. EngineData : 5, #event parameter contains an array of hashes, each containing information about a given engine.
NavComData : 6, #event parameter contains a hash of updated Nav/Com settings NavComData : 6, #event parameter contains a hash of updated Nav/Com settings
NavData : 7, #event parameter contrains a singel { Id: , Value: } tuple requesting a paricular type of NavData NavData : 7, #event parameter contrains a single { Id: , Value: } tuple requesting a particular type of NavData
FMSData : 8, #event parameter containing a hash of updated GPS/FMS information (track, ground-speed, waypoint legs etc.)
ADCData : 8, #event parameter containing a hash of updated Air Data Computer information (track, ground-speed etc.)
DefaultType : "PFDEventNotification", DefaultType : "PFDEventNotification",