1
0
Fork 0

FG1000: EIS Fuel totalizer function

FG1000 requires fuel quantity to be entered manually and uses a flow
computer to calculate the amount used.  Strange but true!
This commit is contained in:
Stuart Buchanan 2019-01-11 20:19:09 +00:00
parent f8eb701d62
commit f32a376a3e
8 changed files with 246 additions and 22 deletions

View file

@ -44,7 +44,7 @@ var EIS =
return obj;
},
updateData : func(engineData) {
updateEngineData : func(engineData) {
me.setTextElement("RPMDisplay", sprintf("%i", engineData.RPM));
me.setTextElement("ManDisplay", sprintf("%.1f", engineData.Man));
me.setTextElement("MBusVolts", sprintf("%.01f", engineData.MBusVolts));
@ -55,16 +55,18 @@ var EIS =
me._oilTempPointer.setValue(engineData.OilTemperatureF);
me._EGTPointer.setValue(engineData.EGTNorm);
me._EGTCylinder.setValue(engineData.EGTNorm);
me._leftFuelPointer.setValue(engineData.LeftFuelUSGal);
me._rightFuelPointer.setValue(engineData.RightFuelUSGal);
me._RPMPointer.setValue(engineData.RPM);
me._ManPointer.setValue(engineData.Man);
},
updateFuelData : func(fuelData) {
me._leftFuelPointer.setValue(fuelData.LeftFuelUSGal);
me._rightFuelPointer.setValue(fuelData.RightFuelUSGal);
},
# Menu tree . engineMenu is referenced from most pages as softkey 0:
# pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EISPage.engineMenu);
engineMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
@ -93,7 +95,7 @@ var EIS =
pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu);
pg.addMenuItem(1, "LEAN", pg, pg.mfd.EIS.leanMenu);
pg.addMenuItem(2, "SYSTEM", pg, pg.mfd.EIS.systemMenu);
pg.addMenuItem(3, "RST FUEL", pg);
pg.addMenuItem(3, "RST FUEL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().setFuelQuantity(0); });
pg.addMenuItem(4, "GAL REM", pg, pg.mfd.EIS.galRemMenu);
pg.addMenuItem(5, "BACK", pg, pg.mfd.EIS.engineMenu);
device.updateMenus();
@ -105,11 +107,11 @@ var EIS =
pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu);
pg.addMenuItem(1, "LEAN", pg, pg.mfd.EIS.leanMenu);
pg.addMenuItem(2, "SYSTEM", pg, pg.mfd.EIS.systemMenu);
pg.addMenuItem(3, "-10 GAL", pg);
pg.addMenuItem(4, "-1 GAL", pg);
pg.addMenuItem(5, "+1 GAL", pg);
pg.addMenuItem(6, "+10 GAL", pg);
pg.addMenuItem(7, "44 GAL", pg);
pg.addMenuItem(3, "-10 GAL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().updateFuelQuantity(-10); } );
pg.addMenuItem(4, "-1 GAL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().updateFuelQuantity(-1); });
pg.addMenuItem(5, "+1 GAL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().updateFuelQuantity(1); });
pg.addMenuItem(6, "+10 GAL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().updateFuelQuantity(10); });
pg.addMenuItem(7, "44 GAL", pg, func(dev, pg, mi) { pg.mfd.EIS.getController().setFuelQuantity(44); });
pg.addMenuItem(8, "BACK", pg, pg.mfd.EIS.engineMenu);
device.updateMenus();
},

View file

@ -46,16 +46,27 @@ var EISController =
"OilPressurePSI",
"OilTemperatureF",
"EGTNorm",
"VacuumSuctionInHG",
"LeftFuelUSGal",
"RightFuelUSGal"];
"VacuumSuctionInHG"];
foreach (var val; elements) {
if (data[val] == nil) data[val] = 0;
}
# Display it
me._page.updateData(data);
me._page.updateEngineData(data);
return emesary.Transmitter.ReceiptStatus_OK;
},
# Function to handle the data provided from the FuelData Emesary Notification.
# This implementation assumes a vector containing hashes of "FuelUSGal" entries
handleFuelData : func (fuelData) {
assert(size(fuelData) > 1, "handleEngineData expects vector of size > 1");
var data = {};
data["LeftFuelUSGal"] = (fuelData[0]["FuelUSGal"] or 0);
data["RightFuelUSGal"] = (fuelData[1]["FuelUSGal"] or 0);
# Display it
me._page.updateFuelData(data);
return emesary.Transmitter.ReceiptStatus_OK;
},
@ -71,10 +82,18 @@ var EISController =
{
if (notification.NotificationType == notifications.PFDEventNotification.DefaultType and
notification.Event_Id == notifications.PFDEventNotification.EngineData and
notification.EventParameter != nil)
notification.EventParameter.Id == "EngineData")
{
return controller.handleEngineData(notification.EventParameter);
return controller.handleEngineData(notification.EventParameter.Value);
}
if (notification.NotificationType == notifications.PFDEventNotification.DefaultType and
notification.Event_Id == notifications.PFDEventNotification.FuelData and
notification.EventParameter.Id == "FuelData")
{
return controller.handleFuelData(notification.EventParameter.Value);
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
};
}
@ -96,4 +115,26 @@ var EISController =
me.DeRegisterWithEmesary();
},
setFuelQuantity : func(val) {
me.sendFuelUpdateNotification("SetFuelQuantity", val);
},
updateFuelQuantity : func(val) {
me.sendFuelUpdateNotification("UpdateFuelQuantity", val);
},
# Send an update to fuel quantities
sendFuelUpdateNotification : func(type, val)
{
# Use Emesary to set the default DTO waypoint
var notification = notifications.PFDEventNotification.new(
"MFD",
me._page.mfd.getDeviceID(),
notifications.PFDEventNotification.FuelData,
{Id: type, Value: val});
var response = me.transmitter.NotifyAll(notification);
if (me.transmitter.IsFailed(response)) print("Failed to set Fuel Data notification " ~ type ~ " " ~ val);
},
};

View file

@ -39,9 +39,6 @@ var GenericEISPublisher =
obj.addPropMap("EGTNorm", "/engines/engine[0]/egt-norm");
obj.addPropMap("VacuumSuctionInHG", "/systems/vacuum/suction-inhg");
obj.addPropMap("LeftFuelUSGal", "/consumables/fuel/tank[0]/indicated-level-gal_us");
obj.addPropMap("RightFuelUSGal", "/consumables/fuel/tank[1]/indicated-level-gal_us");
return obj;
},
@ -62,7 +59,7 @@ var GenericEISPublisher =
"MFD",
1,
notifications.PFDEventNotification.EngineData,
engineData);
{ Id: "EngineData", Value: engineData } );
me._transmitter.NotifyAll(notification);
},

View file

@ -76,8 +76,8 @@ var GenericFMSPublisher =
if (gpsdata["FMSLegDistanceNM"] == -1) gpsdata["FMSLegDistanceNM"] = nil;
# 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 total_fuel = getprop("/consumables/fuel/tank[0]/fg1000-indicated-level-gal_us") or 0.0;
total_fuel = total_fuel + (getprop("/consumables/fuel/tank[1]/fg1000-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;

View file

@ -0,0 +1,103 @@
# 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/>.
#
# Emesary interface to set fuel information, mainly updating fuel levels.
#
var GenericFuelInterface = {
new : func ()
{
var obj = { parents : [ GenericFuelInterface ] };
# Emesary
obj._recipient = nil;
obj._transmitter = emesary.GlobalTransmitter;
obj._registered = 0;
return obj;
},
# Simply update the fuel quantities with the increment. Note that we assume
# the increment is added to both left and right tanks, rather than being a
# total quanity split between tanks.
updateFuelQuantity : func(incr)
{
var fuel = getprop("/consumables/fuel/tank[0]/fg1000-indicated-level-gal_us") + incr;
setprop("/consumables/fuel/tank[0]/fg1000-indicated-level-gal_us", fuel);
fuel = getprop("/consumables/fuel/tank[1]/fg1000-indicated-level-gal_us") + incr;
setprop("/consumables/fuel/tank[1]/fg1000-indicated-level-gal_us", fuel);
},
# Set the fuel quantities. Note that we assume we are setting the value
# to both tanks, rather than splitting between them.
setFuelQuantity : func(val)
{
setprop("/consumables/fuel/tank[0]/fg1000-indicated-level-gal_us", val);
setprop("/consumables/fuel/tank[1]/fg1000-indicated-level-gal_us", val);
},
RegisterWithEmesary : func()
{
if (me._recipient == nil){
me._recipient = emesary.Recipient.new("FuelInterface");
var controller = me;
# Note that unlike the various keys, this data isn't specific to a particular
# Device - it's shared by all. Hence we don't check for the notificaiton
# Device_Id.
me._recipient.Receive = func(notification)
{
if (notification.NotificationType == notifications.PFDEventNotification.DefaultType and
notification.Event_Id == notifications.PFDEventNotification.FuelData and
notification.EventParameter != nil)
{
var id = notification.EventParameter.Id;
if (id == "UpdateFuelQuantity") {
notification.EventParameter.Value = controller.updateFuelQuantity(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
if (id == "SetFuelQuantity") {
notification.EventParameter.Value = controller.setFuelQuantity(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
};
}
me._transmitter.Register(me._recipient);
me._registered = 1;
},
DeRegisterWithEmesary : func()
{
# remove registration from transmitter; but keep the recipient once it is created.
if (me._registered == 1) me._transmitter.DeRegister(me._recipient);
me._registered = 0;
},
start : func() {
me.RegisterWithEmesary();
},
stop : func() {
me.DeRegisterWithEmesary();
},
};

View file

@ -0,0 +1,72 @@
# 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/>.
#
# Fuel Publisher, providing information about fuel tank contents
var GenericFuelPublisher =
{
new : func (frequency=1.0) {
var obj = {
parents : [
GenericFuelPublisher,
PeriodicPropertyPublisher.new(notifications.PFDEventNotification.FuelData, frequency)
],
};
obj.deltaT = frequency;
# Hack to handle most aircraft not having proper engine hours
if (getprop("/engines/engine[0]/hours") == nil) setprop("/engines/engine[0]/hours", 157.0);
# Assume pilot has correct fuel quantities entered at Start of Day
var tanks = props.getNode("/consumables/fuel",1).getChildren("tank");
foreach(var tank; tanks) {
var actual = tank.getNode("level-gal_us", 1).getValue();
var indicatedNode = tank.getNode("fg1000-indicated-level-gal_us", 1);
if (indicatedNode.getValue() == nil) indicatedNode.setValue(actual);
}
return obj;
},
# Custom publish method as we package the values into an array of fuel tanks,
# assuming that fuel is drawn evenly from both tanks.
publish : func() {
var tank_data = [];
var tanks = props.getNode("/consumables/fuel",1).getChildren("tank");
foreach(var tank; tanks) {
var indicatedNode = tank.getNode("fg1000-indicated-level-gal_us", 1);
var fuel = indicatedNode.getValue();
if (fuel == nil) fuel = 0;
var fuel_flow = getprop("/engines/engine[0]/fuel-flow-gph");
if (fuel_flow == nil) fuel_flow = 0;
fuel = fuel - fuel_flow*me.deltaT/3600.0/2;
indicatedNode.setValue(fuel);
append(tank_data, {"FuelUSGal": fuel});
}
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FuelData,
{ Id : "FuelData", Value : tank_data} );
me._transmitter.NotifyAll(notification);
},
};

View file

@ -26,6 +26,8 @@ io.load_nasal(nasal_dir ~ 'Interfaces/GenericNavComUpdater.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/GenericFuelInterface.nas', "fg1000");
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFuelPublisher.nas', "fg1000");
var GenericInterfaceController = {
@ -53,6 +55,8 @@ var GenericInterfaceController = {
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
obj.gpsUpdater = fg1000.GenericFMSUpdater.new();
obj.adcPublisher = fg1000.GenericADCPublisher.new();
obj.fuelPublisher = fg1000.GenericFuelPublisher.new();
obj.fuelInterface = fg1000.GenericFuelInterface.new();
return obj;
},
@ -66,6 +70,8 @@ var GenericInterfaceController = {
me.gpsPublisher.start();
me.gpsUpdater.start();
me.adcPublisher.start();
me.fuelPublisher.start();
me.fuelInterface.start();
},
stop : func() {
@ -77,5 +83,7 @@ var GenericInterfaceController = {
me.gpsPublisher.stop();
me.gpsUpdater.stop();
me.adcPublisher.stop();
me.fuelPublisher.stop();
me.fuelInterface.stop();
},
};

View file

@ -559,6 +559,7 @@ var PFDEventNotification =
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 : 9, #event parameter containing a hash of updated Air Data Computer information (track, ground-speed etc.)
FuelData: 10, #event parameter contains a single { Id: , Value: } tuple either updating or requesting a particular type of fuel data
DefaultType : "PFDEventNotification",