diff --git a/Aircraft/Instruments-3d/FG1000/Models/MFD.svg b/Aircraft/Instruments-3d/FG1000/Models/MFD.svg index 94850366d..a322b6c40 100644 --- a/Aircraft/Instruments-3d/FG1000/Models/MFD.svg +++ b/Aircraft/Instruments-3d/FG1000/Models/MFD.svg @@ -23,11 +23,11 @@ borderopacity="0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="713.25502" - inkscape:cy="157.72368" + inkscape:zoom="7.9999999" + inkscape:cx="803.96414" + inkscape:cy="710.97882" inkscape:document-units="px" - inkscape:current-layer="layer2" + inkscape:current-layer="SurroundGroup" showgrid="true" inkscape:window-width="2495" inkscape:window-height="1416" @@ -65,12 +65,14 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Surround" - style="display:inline" - sodipodi:insensitive="true"> + style="display:inline"> + id="NAV" + inkscape:label="NAV" + style="display:inline" /> + NAV2 PAGE TITLE - - - 123.456 123.456 123.456 123.456 - - - - - - 123.45 - 123.45 + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20.95271873px;line-height:1.25;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold'">123.45 123.45 - 123.45 + 123.45 + 123.45 + x="112.3863" + y="41.656574" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:20.95271873px;line-height:125%;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans Bold';text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ffffff;fill-opacity:1">123.45 XXX - XXX + XXX - - - + x="219.32292" + id="tspan4989-6" + sodipodi:role="line">XXX + + + + + + + + + + + + - - - + - DIS - --.- - ETE - + DIS + --.- + ETE + --:-- - - - --:-- + + + GS - GS + DTK - DTK + TRK - TRK + ETE - ETE + 0 - 0 + 000° - 000° + 000° - 000° + --:-- - - - - --:-- + + + + SoftKey2 - - - SoftKey2 + + + SoftKey1 - - - SoftKey1 + + + SoftKey3 - - - SoftKey3 + + + SoftKey4 - - - SoftKey4 + + + SoftKey6 - - - SoftKey6 + + + SoftKey5 - - - SoftKey5 + + + SoftKey7 - - - SoftKey7 + + + SoftKey8 - - - SoftKey8 + + + SoftKey10 - - - SoftKey10 + + + SoftKey9 - - - SoftKey9 + + + SoftKey11 - - - SoftKey0 + id="SoftKey11" + transform="scale(0.93580799,1.0685953)" + inkscape:label="SoftKey11" + sodipodi:linespacing="0%">SoftKey11 + + + SoftKey0 + + + + + - - - - - - - - - - - image/svg+xml - - - - - - - - - - - NAV2 - NAV1 - - COM2 - COM1 - - PAGE TITLE - - - - 123.456 - 123.456 - 123.456 - 123.456 - - - - - - - 123.45 - 123.45 - 123.45 - 123.45 - XXX - XXX - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DIS - --.- - ETE - --:-- - - - GS - DTK - TRK - ETE - 0 - 000° - 000° - --:-- - - - - SoftKey2 - - - SoftKey1 - - - SoftKey3 - - - SoftKey4 - - - SoftKey6 - - - SoftKey5 - - - SoftKey7 - - - SoftKey8 - - - SoftKey10 - - - SoftKey9 - - - SoftKey11 - - - SoftKey0 - - - - - - Zoom nm - - - - - - OPERATING - OPERATING - - UNRESTRICTED - - - - - - 8NM - - - - - - - - - - - - 8NM - - - - - - - NEAREST NDB - NEAREST VOR - NEAREST USER WAYPOINTS - NEAREST FREQUENCIES - NEAREST AIRSPACES - NEAREST AIRPORTS - NEAREST INTERSECTIONS - - - - - TRIP PLANNING - UTILITY - GPS STATUS - XM RADIO - SYSTEM STATUS - - - - - CHECKLIST 1 - CHECKLIST 2 - CHECKLIST 3 - CHECKLIST 4 - CHECKLIST 5 - - - - - AIRPORT INFORMATION - INTERSECTION INFORMATION - NDB INFORMATION - VOR INFORMATION - USER WPT INFORMATION - - - - - NAVIGATION MAP - TRAFFIC MAP - STORMSCOPE - WEATHER DATA LINK - TAWS-B - - - - - ACTIVE FLIGHT PLAN - FLIGHT PLAN CATALOG - STORED FLIGHT PLAN - - MAP - WPT - AUX - FPL - LST - NRST - - diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Drivers/EISDriver.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Drivers/EISDriver.nas deleted file mode 100644 index 5d4803d45..000000000 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Drivers/EISDriver.nas +++ /dev/null @@ -1,68 +0,0 @@ -# FG1000 Engine Information Display Default Driver -# -# Driver values in the EIS. - -var PropMap = -{ - new : func(name, property) - { - var obj = { parents : [ PropMap ] }; - obj._name = name; - obj._val = 0; - obj._prop = globals.props.getNode(property, 1); - obj._val = obj._prop.getValue(); - return obj; - }, - - update : func() - { - me._val = me._prop.getValue(); - }, - - getValue : func() - { - return me._val; - } - -}; - -var EISDriver = -{ - new : func() - { - var obj = { parents : [ EISDriver ] }; - - # Hack to handle most aircraft not having proper engine hours - setprop("/engines/engine[0]/hours", 157.0); - - obj._propmap = { - "RPM" : PropMap.new("RPM", "/engines/engine[0]/rpm"), - "MBusVolts" : PropMap.new("MBusVolts", "/systems/electrical/volts"), - "EngineHours" : PropMap.new("EngineHours", "/engines/engine[0]/hours"), - "FuelFlowGPH" : PropMap.new("FuelFlowGPH", "/engines/engine[0]/fuel-flow-gph"), - "OilPressurePSI" : PropMap.new("OilPressurePSI", "/engines/engine[0]/oil-pressure-psi"), - "OilTemperatureF" : PropMap.new("OilTemperatureF", "/engines/engine[0]/oil-temperature-degf"), - "EGTNorm" : PropMap.new("EGTNorm", "/engines/engine[0]/egt-norm"), - "VacuumSuctionInHG" : PropMap.new("VacuumSuctionInHG", "/systems/vacuum/suction-inhg"), - - "LeftFuelUSGal" : PropMap.new("LeftFuelUSGal", "/consumables/fuel/tank[0]/indicated-level-gal_us"), - "RightFuelUSGal" : PropMap.new("RightFuelUSGal", "/consumables/fuel/tank[1]/indicated-level-gal_us"), - - - }; - return obj; - }, - - getValue : func(name) - { - if (me._propmap[name] == nil) print("Unknown Driver Key in EISDriver.nas " ~ name); - return me._propmap[name].getValue(); - }, - - update: func () { - - foreach (var tp; keys(me._propmap)) { - me._propmap[tp].update(); - } - } -}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EIS.nas b/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EIS.nas index 7e1afecc1..7942dc373 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EIS.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EIS.nas @@ -30,21 +30,21 @@ var EIS = }, updateData : func(engineData) { - obj.setTextElement("RPMDisplay", sprintf("%i", engineData.RPM)); - obj.setTextElement("MBusVolts", sprintf("%.01f", engineData.MBusVolts)); - obj.setTextElement("EBusVolts", sprintf("%.01f", engineData.MBusVolts)); # TODO: Include Emergency Bus - obj.setTextElement("EngineHours", sprintf("%.01f", engineData.EngineHours)); + me.setTextElement("RPMDisplay", sprintf("%i", engineData.RPM)); + me.setTextElement("MBusVolts", sprintf("%.01f", engineData.MBusVolts)); + me.setTextElement("EBusVolts", sprintf("%.01f", engineData.MBusVolts)); # TODO: Include Emergency Bus + me.setTextElement("EngineHours", sprintf("%.01f", engineData.EngineHours)); - obj._fuelFlowPointer.setValue(engineData.FuelFlowGPH); - obj._oilPressurePointer.setValue(engineData.OilPressurePSI); - obj._oilTempPointer.setValue(engineData.OilTemperatureF); - obj._EGTPointer.setValue(engineData.EGTNorm); - obj._EGTCylinder.setValue(engineData.EGTNorm); - obj._vacPointer.setValue(engineData.VacuumSuctionInHG); - obj._leftFuelPointer.setValue(engineData.LeftFuelUSGal); - obj._rightFuelPointer.setValue(engineData.RightFuelUSGal); + me._fuelFlowPointer.setValue(engineData.FuelFlowGPH); + me._oilPressurePointer.setValue(engineData.OilPressurePSI); + me._oilTempPointer.setValue(engineData.OilTemperatureF); + me._EGTPointer.setValue(engineData.EGTNorm); + me._EGTCylinder.setValue(engineData.EGTNorm); + me._vacPointer.setValue(engineData.VacuumSuctionInHG); + me._leftFuelPointer.setValue(engineData.LeftFuelUSGal); + me._rightFuelPointer.setValue(engineData.RightFuelUSGal); - obj._RPMPointer.setValue(engineData.RPM); + me._RPMPointer.setValue(engineData.RPM); }, # Menu tree . engineMenu is referenced from most pages as softkey 0: diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EISController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EISController.nas index d43afd457..acec7eb93 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EISController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/EIS/EISController.nas @@ -38,7 +38,8 @@ var EISController = } # Display it - me.page.upateData(data); + me._page.updateData(data); + return emesary.Transmitter.ReceiptStatus_OK; }, RegisterWithEmesary : func(transmitter = nil){ diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericEISPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericEISPublisher.nas new file mode 100644 index 000000000..7fe8a1d98 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericEISPublisher.nas @@ -0,0 +1,41 @@ +# EIS Driver using Emesary for a single engined aircraft, e.g. Cessna 172. +var GenericEISPublisher = +{ + + new : func (frequency=0.25, transmitter = nil) { + var obj = { + parents : [ GenericEISPublisher, PropertyPublisher.new(frequency, transmitter) ], + }; + + # Hack to handle most aircraft not having proper engine hours + if (getprop("/engines/engine[0]/hours") == nil) setprop("/engines/engine[0]/hours", 157.0); + + obj.addPropMap("RPM", "/engines/engine[0]/rpm"); + obj.addPropMap("MBusVolts", "/systems/electrical/volts"); + obj.addPropMap("EngineHours", "/engines/engine[0]/hours"); + obj.addPropMap("FuelFlowGPH", "/engines/engine[0]/fuel-flow-gph"); + obj.addPropMap("OilPressurePSI", "/engines/engine[0]/oil-pressure-psi"); + obj.addPropMap("OilTemperatureF", "/engines/engine[0]/oil-temperature-degf"); + 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; + }, + + publish : func() { + var engineData0 = {}; + + foreach (var propmap; me._propmaps) { + var name = propmap.getName(); + engineData0[name] = propmap.getValue(); + } + + var engineData = []; + append(engineData, engineData0); + + me.notify(notifications.PFDEventNotification.EngineData, engineData); + }, +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas new file mode 100644 index 000000000..a9e995440 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas @@ -0,0 +1,57 @@ +# NavCom Interface using Emesary for a simple dual Nav/Com system using standard properties +var GenericNavComPublisher = +{ + new : func (frequency=0.25, transmitter = nil) { + var obj = { + parents : [ GenericNavComPublisher, PropertyPublisher.new(frequency, transmitter) ], + }; + + # Hack to handle cases where there is no selected COMM or NAV frequency + if (getprop("/instrumentation/com-selected") == nil) setprop("/instrumentation/com-selected", 1); + if (getprop("/instrumentation/nav-selected") == nil) setprop("/instrumentation/nav-selected", 1); + + obj.addPropMap("Comm1SelectedFreq", "/instrumentation/comm/frequencies/selected-mhz"); + obj.addPropMap("Comm1StandbyFreq", "/instrumentation/comm/frequencies/selected-mhz"); + obj.addPropMap("Comm1AirportID", "/instrumentation/comm/airport-id"); + obj.addPropMap("Comm1StationName", "/instrumentation/comm/station-name"); + obj.addPropMap("Comm1StationType", "/instrumentation/comm/station-type"); + obj.addPropMap("Comm1Volume", "/instrumentation/comm/volume"); + obj.addPropMap("Comm1Serviceable", "/instrumentation/comm/serviceable"); + + obj.addPropMap("Comm2SelectedFreq", "/instrumentation/comm[1]/frequencies/selected-mhz"); + obj.addPropMap("Comm2StandbyFreq", "/instrumentation/comm[1]/frequencies/selected-mhz"); + obj.addPropMap("Comm2AirportID", "/instrumentation/comm[1]/airport-id"); + obj.addPropMap("Comm2StationName", "/instrumentation/comm[1]/station-name"); + obj.addPropMap("Comm2StationType", "/instrumentation/comm[1]/station-type"); + obj.addPropMap("Comm2Volume", "/instrumentation/comm[1]/volume"); + obj.addPropMap("Comm2Serviceable", "/instrumentation/comm[1]/serviceable"); + + obj.addPropMap("CommSelected", "/instrumentation/com-selected"); + + obj.addPropMap("Nav1SelectedFreq", "/instrumentation/nav/frequencies/selected-mhz"); + obj.addPropMap("Nav1StandbyFreq", "/instrumentation/nav/frequencies/selected-mhz"); + obj.addPropMap("Nav1ID", "/instrumentation/nav/nav-id"); + obj.addPropMap("Nav1Serviceable", "/instrumentation/nav/serviceable"); + + obj.addPropMap("Nav2SelectedFreq", "/instrumentation/nav[1]/frequencies/selected-mhz"); + obj.addPropMap("Nav2StandbyFreq", "/instrumentation/nav[1]/frequencies/selected-mhz"); + obj.addPropMap("Nav2ID", "/instrumentation/nav[1]/nav-id"); + obj.addPropMap("Nav2Serviceable", "/instrumentation/nav[1]/serviceable"); + + obj.addPropMap("NavSelected", "/instrumentation/nav-selected"); + + + return obj; + }, + + publish : func() { + var data = {}; + + foreach (var propmap; me._propmaps) { + var name = propmap.getName(); + data[name] = propmap.getValue(); + } + + me.notify(notifications.PFDEventNotification.NavComData, data); + }, +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyPublisher.nas new file mode 100644 index 000000000..e9c97e959 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyPublisher.nas @@ -0,0 +1,60 @@ +# Generic PropertyPublisher class for the FG1000 MFD using Emesary +# Publishes property values to Emesary for consumption by the MFD + +var PropertyPublisher = +{ + + PropMap : { + new : func(name, property) + { + var obj = { parents : [ PropertyPublisher.PropMap ] }; + obj._name = name; + obj._prop = globals.props.getNode(property, 1); + return obj; + }, + + getName : func() { return me._name; }, + getValue : func() { return me._prop.getValue(); }, + }, + + new : func (frequency=0.25, transmitter = nil) { + var obj = { + parents : [ PropertyPublisher ], + _transmitter : transmitter, + _frequency : frequency, + _propmaps : [], + }; + + if (obj._transmitter == nil) obj._transmitter = emesary.GlobalTransmitter; + + obj._publishTimer = nil; + + return obj; + }, + + addPropMap : func(name, prop) { + append(me._propmaps, PropertyPublisher.PropMap.new(name, prop)); + }, + + publish : func() { + }, + + notify : func(notification, data) { + var notification = notifications.PFDEventNotification.new( + "MFD", + 1, + notification, + data); + + me._transmitter.NotifyAll(notification); + }, + + start : func() { + me._timer = maketimer(me._frequency, me, me.publish); + me._timer.start(); + }, + stop : func() { + if(me._timer != nil) me._timer.stop(); + me._timer = nil; + }, +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyUpdater.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyUpdater.nas new file mode 100644 index 000000000..9ecf20722 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/PropertyUpdater.nas @@ -0,0 +1,93 @@ +# Generic class to update properties from Emesary for the MFD +# +# In the simplest cases where the Emesary EventParameter for the specified +# Event ID is a hash whose values can be mapped directly to property values, +# it can be used directly. For more complex cases, the handleNotificationEvent +# method should be over-ridden, and should return +# emesary.Transmitter.ReceiptStatus_OK or equivalent ReceiptStatus value. + +var PropertyUpdater = +{ + + PropMap : { + new : func(name, property) + { + var obj = { parents : [ PropertyUpdater.PropMap ] }; + obj._name = name; + obj._prop = globals.props.getNode(property, 1); + return obj; + }, + + getName : func() { return me._name; }, + getValue : func() { return me._prop.getValue(); }, + }, + + new : func (device, notificationType, eventID, transmitter = nil) { + var obj = { + parents : [ Interface ], + _device : device, + _notificationType : notificationType, + _transmitter : transmitter, + _recipient : recipient, + _propmaps : {}, + }; + + if (obj._transmitter == nil) obj._transmitter = emesary.GlobalTransmitter; + + return obj; + }, + + addPropMap : func(name, prop) { + me._propmaps[name] = PropertyPublisher.PropMap.new(name, prop); + }, + + handleNotificationEvent : func(eventParameter) { + + var retval = emesary.Transmitter.ReceiptStatus_NotProcessed; + foreach(var name; keys(eventParameters)) { + if (me._propmaps[name] != nil) { + me._propmaps[name].setValue(eventParameters[name]) + retval = emesary.Transmitter.ReceiptStatus_OK; + } + } + + return retval; + }, + + RegisterWithEmesary : func(){ + + if (me._recipient == nil){ + me._recipient = emesary.Recipient.new("AirportInfoController_" ~ me._page.device.designation); + var pfd_obj = me._device; + var controller = me; + me._recipient.Receive = func(notification) + { + if (notification.Device_Id == pfd_obj.device_id + and notification.NotificationType == me._notificationType) { + if (notification.Event_Id == me._eventID + and notification.EventParameter != nil) + { + return me.handleNotificationEvent(notification.EventParameter); + } + } + return emesary.Transmitter.ReceiptStatus_NotProcessed; + }; + } + transmitter.Register(me._recipient); + me.transmitter = transmitter; + }, + DeRegisterWithEmesary : func(transmitter = nil){ + # remove registration from transmitter; but keep the recipient once it is created. + if (me.transmitter != nil) + me.transmitter.DeRegister(me._recipient); + me.transmitter = nil; + }, + + start : func() { + me.RegisterWithEmesary(); + }, + stop : func() { + me.DeRegisterWithEmesary(); + }, + +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas index 6a2ec55f1..548e62c85 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas @@ -11,6 +11,7 @@ var nasal_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/FG1000/Nasal io.load_nasal(nasal_dir ~ '/MFDPage.nas', "fg1000"); var MFDPages = [ + "Surround", "NavigationMap", "EIS", "TrafficMap", @@ -58,8 +59,6 @@ foreach (var page; MFDPages) { io.load_nasal(nasal_dir ~ page ~ '/' ~ page ~ 'Controller.nas', "fg1000"); } -io.load_nasal(nasal_dir ~ 'PageGroupController.nas', "fg1000"); - var MFD = { new : func (myCanvas) @@ -68,8 +67,7 @@ var MFD = parents : [ MFD ], EIS : nil, NavigationMap: nil, - - + Surround : nil, }; obj._svg = myCanvas.createGroup("softkeys"); @@ -101,26 +99,28 @@ var MFD = # Surround dynamic elements obj._pageTitle = obj._svg.getElementById("PageTitle"); - # Controller for the display on the bottom left which allows selection + # Controller for the header and display on the bottom left which allows selection # of page groups and individual pages using the FMS controller. - obj._pageGroupController = fg1000.PageGroupController.new(myCanvas, obj._svg, obj._MFDDevice); + obj.Surround = fg1000.Surround.new(obj, myCanvas, obj._MFDDevice, obj._svg); + obj._pageGroupController = obj.Surround.controller; # Engine Information System. A special case as it's always displayed on the MFD. - obj.EIS = obj._pageGroupController.addPage("EIS", fg1000.EIS.new(obj, myCanvas, obj._MFDDevice, obj._svg)); + obj.EIS = obj.Surround.addPage("EIS", fg1000.EIS.new(obj, myCanvas, obj._MFDDevice, obj._svg)); # The NavigationMap page is a special case, as it is displayed with the Nearest... pages as an overlay - obj.NavigationMap = obj._pageGroupController.addPage("NavigationMap", fg1000.NavigationMap.new(obj, myCanvas, obj._MFDDevice, obj._svg)); + obj.NavigationMap = obj.Surround.addPage("NavigationMap", fg1000.NavigationMap.new(obj, myCanvas, obj._MFDDevice, obj._svg)); obj.NavigationMap.topMenu(obj._MFDDevice, obj.NavigationMap, nil); foreach (var page; MFDPages) { - if (page != "NavigationMap") { - var code = "obj._pageGroupController.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));"; + if ((page != "NavigationMap") and (page != "EIS")) { + var code = "obj.Surround.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));"; var addPageFn = compile(code); addPageFn(); } } - # Display the EIS and NavMap and the appropriate top level on startup. + # Display the Surround, EIS and NavMap and the appropriate top level on startup. + obj.Surround.setVisible(1); obj.EIS.setVisible(1); obj.EIS.ondisplay(); obj._MFDDevice.selectPage(obj.NavigationMap); @@ -142,6 +142,7 @@ var MFD = { me._MFDDevice.current_page.offdisplay(); me._MFDDevice.DeRegisterWithEmesary(); + me._pageGroupController.del(); }, setPageTitle: func(title) diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NearestAirports/NearestAirportsController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NearestAirports/NearestAirportsController.nas index 7f4c5342d..58cd39aaf 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NearestAirports/NearestAirportsController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NearestAirports/NearestAirportsController.nas @@ -72,6 +72,7 @@ var NearestAirportsController = handleCRSR : func() { me._crsrToggle = (! me._crsrToggle); if (me._crsrToggle) { + me.page.topMenu(me.page.device, me.page, nil); me.page.selectAirports(); me.selectAirports(); } else { diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/PageGroupController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/PageGroupController.nas deleted file mode 100644 index a2c87399d..000000000 --- a/Aircraft/Instruments-3d/FG1000/Nasal/PageGroupController.nas +++ /dev/null @@ -1,169 +0,0 @@ -# Controller for the PageGroup navigation, displayed in the bottom right of the -# FMS, and controlled by the FMS knob - -# Set of pages, references by SVG ID -var PAGE_GROUPS = [ - - { label: "MapPageGroupLabel", - group: "MapPageGroup", - pages: [ "NavigationMap", "TrafficMap", "Stormscope", "WeatherDataLink", "TAWSB"], - }, - { label: "WPTGroupLabel", - group: "WPTPageGroup", - pages: [ "AirportInfo", "IntersectionInfo", "NDBInfo", "VORInfo", "UserWPTInfo"], - }, - - { label: "AuxGroupLabel", - group: "AuxPageGroup", - pages: [ "TripPlanning", "Utility", "GPSStatus", "XMRadio", "SystemStatus"], - }, - - { label: "FPLGroupLabel", - group: "FPLPageGroup", - pages: [ "ActiveFlightPlanWide", "FlightPlanCatalog", "StoredFlightPlan"], - }, - - { label: "LstGroupLabel", - group: "LstPageGroup", - pages: [ "Checklist1", "Checklist2", "Checklist3", "Checklist4", "Checklist5"], - }, - - { label: "NrstGroupLabel", - group: "NrstPageGroup", - pages: [ "NearestAirports", "NearestIntersections", "NearestNDB", "NearestVOR", "NearestUserWaypoints", "NearestFrequencies", "NearestAirspaces"], - } -]; - -var PageGroupController = -{ - new : func (myCanvas, svg, device) - { - var obj = { parents : [ PageGroupController ] }; - obj._canvas = myCanvas; - obj._svg = svg; - obj._device = device; - obj._menuVisible = 0; - obj._selectedPageGroup = 0; - obj._selectedPage = 0; - - # List of pages to be controllers. Keys are the pages in PAGE_GROUPS; - obj._pageList = {}; - obj._elements = {}; - - foreach (var pageGroup; PAGE_GROUPS) { - var group = svg.getElementById(pageGroup.group); - var label = svg.getElementById(pageGroup.label); - assert(group != nil, "Unable to find element " ~ pageGroup.group); - assert(label != nil, "Unable to find element " ~ pageGroup.label); - obj._elements[pageGroup.group] = group; - obj._elements[pageGroup.label] = label; - - foreach(var pg; pageGroup.pages) { - var page = svg.getElementById(pg); - assert(page != nil, "Unable to find element " ~ pg); - obj._elements[pg] = page; - } - } - - # Timers to control when to hide the menu after inactivity, and when to load - # a new page. - obj._hideMenuTimer = maketimer(3, obj, obj.hideMenu); - obj._hideMenuTimer.singleShot = 1; - - obj._loadPageTimer = maketimer(0.5, obj, obj.loadPage); - obj._loadPageTimer.singleShot = 1; - - obj.hideMenu(); - return obj; - }, - - addPage : func(name, page) - { - me._pageList[name] = page; - }, - - getPage : func(name) - { - return me._pageList[name]; - }, - - hideMenu : func() - { - foreach(var pageGroup; PAGE_GROUPS) - { - me._elements[pageGroup.group].setVisible(0); - me._elements[pageGroup.label].setVisible(0); - } - me._menuVisible = 0; - }, - - # Function to change a page based on the selection - loadPage : func() - { - var pageToLoad = PAGE_GROUPS[me._selectedPageGroup].pages[me._selectedPage]; - var page = me._pageList[pageToLoad]; - - assert(page != nil, "Unable to find page " ~ pageToLoad); - me._device.selectPage(page); - }, - showMenu : func() - { - foreach(var pageGroup; PAGE_GROUPS) - { - if (PAGE_GROUPS[me._selectedPageGroup].label == pageGroup.label) - { - # Display the page group and highlight the label - me._elements[pageGroup.group].setVisible(1); - me._elements[pageGroup.label].setVisible(1); - me._elements[pageGroup.label].setColor(0.7,0.7,1.0); - - foreach (var page; pageGroup.pages) - { - # Highlight the current page. - if (pageGroup.pages[me._selectedPage] == page) { - me._elements[page].setColor(0.7,0.7,1.0); - } else { - me._elements[page].setColor(0.7,0.7,0.7); - } - } - } - else - { - # Hide the pagegroup and unhighlight the label on the bottom - me._elements[pageGroup.group].setVisible(0); - me._elements[pageGroup.label].setVisible(1); - me._elements[pageGroup.label].setColor(0.7,0.7,0.7); - } - } - me._menuVisible = 1; - me._hideMenuTimer.stop(); - me._hideMenuTimer.restart(3); - me._loadPageTimer.stop(); - me._loadPageTimer.restart(0.5); - - }, - - handleFMSOuter : func(val) - { - if (me._menuVisible == 1) { - # Change page group - var incr_or_decr = (val > 0) ? 1 : -1; - me._selectedPageGroup = math.mod(me._selectedPageGroup + incr_or_decr, size(PAGE_GROUPS)); - me._selectedPage = 0; - } - me.showMenu(); - return emesary.Transmitter.ReceiptStatus_Finished; - }, - - handleFMSInner : func(val) - { - if (me._menuVisible == 1) { - # Change page group - var incr_or_decr = (val > 0) ? 1 : -1; - me._selectedPage = math.mod(me._selectedPage + incr_or_decr, size(PAGE_GROUPS[me._selectedPageGroup].pages)); - } - me.showMenu(); - return emesary.Transmitter.ReceiptStatus_Finished; - - }, -}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Surround/Surround.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/Surround.nas new file mode 100644 index 000000000..1662f7aa5 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/Surround.nas @@ -0,0 +1,254 @@ +# MFD Surround +# +# Header fields at the top of the page +# +# PageGroup navigation, displayed in the bottom right of the +# FMS, and controlled by the FMS knob + +# Set of pages, references by SVG ID +var PAGE_GROUPS = [ + + { label: "MapPageGroupLabel", + group: "MapPageGroup", + pages: [ "NavigationMap", "TrafficMap", "Stormscope", "WeatherDataLink", "TAWSB"], + }, + { label: "WPTGroupLabel", + group: "WPTPageGroup", + pages: [ "AirportInfo", "IntersectionInfo", "NDBInfo", "VORInfo", "UserWPTInfo"], + }, + + { label: "AuxGroupLabel", + group: "AuxPageGroup", + pages: [ "TripPlanning", "Utility", "GPSStatus", "XMRadio", "SystemStatus"], + }, + + { label: "FPLGroupLabel", + group: "FPLPageGroup", + pages: [ "ActiveFlightPlanWide", "FlightPlanCatalog", "StoredFlightPlan"], + }, + + { label: "LstGroupLabel", + group: "LstPageGroup", + pages: [ "Checklist1", "Checklist2", "Checklist3", "Checklist4", "Checklist5"], + }, + + { label: "NrstGroupLabel", + group: "NrstPageGroup", + pages: [ "NearestAirports", "NearestIntersections", "NearestNDB", "NearestVOR", "NearestUserWaypoints", "NearestFrequencies", "NearestAirspaces"], + } +]; + +var Surround = +{ + new : func (mfd, myCanvas, device, svg) + { + var obj = { parents : [ + Surround, + MFDPage.new(mfd, myCanvas, device, svg, "Surround", ""), + ] }; + + var textElements = [ + "Comm1StandbyFreq", "Comm1SelectedFreq", + "Comm2StandbyFreq", "Comm2SelectedFreq", + "Nav1StandbyFreq", "Nav1SelectedFreq", + "Nav2StandbyFreq", "Nav2SelectedFreq", + ]; + + obj.addTextElements(textElements); + + obj._comm1selected = PFD.HighlightElement.new(obj.pageName, svg, "Comm1Selected", "Comm1"); + obj._comm2selected = PFD.HighlightElement.new(obj.pageName, svg, "Comm2Selected", "Comm2"); + + obj._nav1selected = PFD.HighlightElement.new(obj.pageName, svg, "Nav1Selected", "Nav1"); + obj._nav2selected = PFD.HighlightElement.new(obj.pageName, svg, "Nav2Selected", "Nav2"); + + obj._comm1failed = PFD.HighlightElement.new(obj.pageName, svg, "Comm1Failed", "Comm1"); + obj._comm2failed = PFD.HighlightElement.new(obj.pageName, svg, "Comm2Failed", "Comm2"); + + obj._nav1failed = PFD.HighlightElement.new(obj.pageName, svg, "Nav1Failed", "Nav1"); + obj._nav2failed = PFD.HighlightElement.new(obj.pageName, svg, "Nav2Failed", "Nav2"); + + obj._canvas = myCanvas; + obj._menuVisible = 0; + obj._selectedPageGroup = 0; + obj._selectedPage = 0; + + # List of pages to be controllers. Keys are the pages in PAGE_GROUPS; + obj._pageList = {}; + obj._elements = {}; + + foreach (var pageGroup; PAGE_GROUPS) { + var group = svg.getElementById(pageGroup.group); + var label = svg.getElementById(pageGroup.label); + assert(group != nil, "Unable to find element " ~ pageGroup.group); + assert(label != nil, "Unable to find element " ~ pageGroup.label); + obj._elements[pageGroup.group] = group; + obj._elements[pageGroup.label] = label; + + foreach(var pg; pageGroup.pages) { + var page = svg.getElementById(pg); + assert(page != nil, "Unable to find element " ~ pg); + obj._elements[pg] = page; + } + } + + # Timers to control when to hide the menu after inactivity, and when to load + # a new page. + obj._hideMenuTimer = maketimer(3, obj, obj.hideMenu); + obj._hideMenuTimer.singleShot = 1; + + obj._loadPageTimer = maketimer(0.5, obj, obj.loadPage); + obj._loadPageTimer.singleShot = 1; + + obj.hideMenu(); + + obj.controller = fg1000.SurroundController.new(obj, svg); + return obj; + }, + + handleNavComData : func(data) { + foreach(var name; keys(data)) { + var val = data[name]; + + if (name == "Comm1SelectedFreq") me.setTextElement("Comm1SelectedFreq", sprintf("%0.03f", val)); + if (name == "Comm1StandbyFreq") me.setTextElement("Comm1StandbyFreq", sprintf("%0.03f", val)); + if (name == "Comm1Serviceable") { + if (val == 1) { + me._comm1failed.unhighlightElement() + } else { + me._comm1failed.highlightElement(); + } + } + + if (name == "Comm2SelectedFreq") me.setTextElement("Comm2SelectedFreq", sprintf("%0.03f", val)); + if (name == "Comm2StandbyFreq") me.setTextElement("Comm2StandbyFreq", sprintf("%0.03f", val)); + if (name == "Comm2Serviceable") { + if (val == 1) { + me._comm2failed.unhighlightElement(); + } else { + me._comm2failed.highlightElement(); + } + } + + if (name == "CommSelected") { + if (val == 1) { + me._comm1selected.highlightElement(); + me._comm2selected.unhighlightElement(); + } else { + me._comm1selected.unhighlightElement(); + me._comm2selected.highlightElement(); + } + } + + if (name == "Nav1SelectedFreq") me.setTextElement("Nav1SelectedFreq", sprintf("%0.03f", val)); + if (name == "Nav1StandbyFreq") me.setTextElement("Nav1StandbyFreq", sprintf("%0.03f", val)); + if (name == "Nav1Serviceable") { + if (val == 1) { + me._nav1failed.unhighlightElement(); + } else { + me._nav1failed.highlightElement(); + } + } + + if (name == "Nav2SelectedFreq") me.setTextElement("Nav2SelectedFreq", sprintf("%0.03f", val)); + if (name == "Nav2StandbyFreq") me.setTextElement("Nav2StandbyFreq", sprintf("%0.03f", val)); + if (name == "Nav2Serviceable") { + if (val == 1) { + me._nav2failed.unhighlightElement(); + } else { + me._nav2failed.highlightElement(); + } + } + + if (name == "NavSelected") { + if (val == 1) { + me._nav1selected.highlightElement(); + me._nav2selected.unhighlightElement(); + } else { + me._nav1selected.unhighlightElement(); + me._nav2selected.highlightElement(); + } + } + } + }, + + addPage : func(name, page) + { + me._pageList[name] = page; + }, + + getPage : func(name) + { + return me._pageList[name]; + }, + + # Function to change a page based on the selection + loadPage : func() + { + var pageToLoad = PAGE_GROUPS[me._selectedPageGroup].pages[me._selectedPage]; + var page = me._pageList[pageToLoad]; + + assert(page != nil, "Unable to find page " ~ pageToLoad); + me.device.selectPage(page); + }, + incrPageGroup : func(val) { + var incr_or_decr = (val > 0) ? 1 : -1; + me._selectedPageGroup = math.mod(me._selectedPageGroup + incr_or_decr, size(PAGE_GROUPS)); + me._selectedPage = 0; + }, + incrPage : func(val) { + var incr_or_decr = (val > 0) ? 1 : -1; + me._selectedPage = math.mod(me._selectedPage + incr_or_decr, size(PAGE_GROUPS[me._selectedPageGroup].pages)); + }, + showMenu : func() + { + foreach(var pageGroup; PAGE_GROUPS) + { + if (PAGE_GROUPS[me._selectedPageGroup].label == pageGroup.label) + { + # Display the page group and highlight the label + me._elements[pageGroup.group].setVisible(1); + me._elements[pageGroup.label].setVisible(1); + me._elements[pageGroup.label].setColor(0.7,0.7,1.0); + + foreach (var page; pageGroup.pages) + { + # Highlight the current page. + if (pageGroup.pages[me._selectedPage] == page) { + me._elements[page].setColor(0.7,0.7,1.0); + } else { + me._elements[page].setColor(0.7,0.7,0.7); + } + } + } + else + { + # Hide the pagegroup and unhighlight the label on the bottom + me._elements[pageGroup.group].setVisible(0); + me._elements[pageGroup.label].setVisible(1); + me._elements[pageGroup.label].setColor(0.7,0.7,0.7); + } + } + me._menuVisible = 1; + me._hideMenuTimer.stop(); + me._hideMenuTimer.restart(3); + me._loadPageTimer.stop(); + me._loadPageTimer.restart(0.5); + + }, + hideMenu : func() + { + foreach(var pageGroup; PAGE_GROUPS) + { + me._elements[pageGroup.group].setVisible(0); + me._elements[pageGroup.label].setVisible(0); + } + me._menuVisible = 0; + }, + isMenuVisible : func() + { + return me._menuVisible; + }, + + +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundController.nas new file mode 100644 index 000000000..4b41c53ce --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundController.nas @@ -0,0 +1,81 @@ +# Surround Controller +var SurroundController = +{ + new : func (page, svg) + { + var obj = { + parents : [ SurroundController ], + _recipient : nil, + _page : page, + }; + + obj.RegisterWithEmesary(); + return obj; + }, + + del : func() { + me.DeRegisterWithEmesary(); + }, + + handleNavComData : func(values) { + # pass straight through the to page - we have nothing to do. + me._page.handleNavComData(values); + return emesary.Transmitter.ReceiptStatus_OK; + }, + + # These methods are slightly unusual in that they are called by other + # controllers when the CRSR is not active. Hence they aren't referenced + # in the RegisterWithEmesary call below. + # + handleFMSOuter : func(val) + { + if (me._page.isMenuVisible()) { + # Change page group + me._page.incrPageGroup(val); + } + me._page.showMenu(); + return emesary.Transmitter.ReceiptStatus_Finished; + }, + + handleFMSInner : func(val) + { + if (me._page.isMenuVisible()) { + # Change page group + me.incrPage(val); + } + me.showMenu(); + return emesary.Transmitter.ReceiptStatus_Finished; + }, + + RegisterWithEmesary : func(transmitter = nil){ + if (transmitter == nil) + transmitter = emesary.GlobalTransmitter; + + if (me._recipient == nil){ + me._recipient = emesary.Recipient.new("PageGroupController_" ~ me._page.device.designation); + var pfd_obj = me._page.device; + var controller = me; + me._recipient.Receive = func(notification) + { + if (notification.Device_Id == pfd_obj.device_id + and notification.NotificationType == notifications.PFDEventNotification.DefaultType) { + if (notification.Event_Id == notifications.PFDEventNotification.NavComData + and notification.EventParameter != nil) + { + return controller.handleNavComData(notification.EventParameter); + } + } + return emesary.Transmitter.ReceiptStatus_NotProcessed; + }; + } + transmitter.Register(me._recipient); + me.transmitter = transmitter; + }, + DeRegisterWithEmesary : func(transmitter = nil){ + # remove registration from transmitter; but keep the recipient once it is created. + if (me.transmitter != nil) + me.transmitter.DeRegister(me._recipient); + me.transmitter = nil; + }, + +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundOptions.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundOptions.nas new file mode 100644 index 000000000..26cc60a73 --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundOptions.nas @@ -0,0 +1,28 @@ +# Surround Options +var SurroundOptions = +{ + new : func() { + var obj = { parents : [SurroundOptions] }; + obj.Options= {}; + obj.loadOptions(); + return obj; + }, + + getOption : func(type) { + return me.Options[type]; + }, + + setOption : func(type, name, value) { + me.Options[type][name] = value; + }, + + loadOptions : func() { + me.clearOptions(); + me.Options.APS = {}; + }, + + clearOptions : func() { + me.Options = {}; + }, + +}; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundStyles.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundStyles.nas new file mode 100644 index 000000000..587d4eafc --- /dev/null +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Surround/SurroundStyles.nas @@ -0,0 +1,28 @@ +# Surround Styles +var SurroundStyles = +{ + new : func() { + var obj = { parents : [ SurroundStyles ]}; + obj.Styles = {}; + obj.loadStyles(); + return obj; + }, + + getStyle : func(type) { + return me.Styles[type]; + }, + + setStyle : func(type, name, value) { + me.Styles[type][name] = value; + }, + + loadStyles : func() { + me. clearStyles(); + me.Styles.XXX = {}; + }, + + clearStyles : func() { + me.Styles = {}; + }, + +}; diff --git a/Nasal/notifications.nas b/Nasal/notifications.nas index 9cf08d173..433219ae2 100644 --- a/Nasal/notifications.nas +++ b/Nasal/notifications.nas @@ -545,6 +545,7 @@ var PFDEventNotification = # 3 Change softkey button text # 4 hardkey pushed - i.e. non-soft keys that don't change function based on context. # 5 Engine data - e.g. RPM, EGTs, CHTs for display purposes +# 6 NavCom data - e.g. frequencies, volume, TX, RX for each of the COM and NAV radios. # _event_param - param related to the event ID. implementation specific. ## SoftKeyPushed : 1, @@ -552,6 +553,7 @@ var PFDEventNotification = ChangeMenuText : 3, #event parameter contains array of { Id: , Text: } tuples 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. + NavComData : 6, #event paramterr contains a hash of updated Nav/Com settings DefaultType : "PFDEventNotification", diff --git a/gui/dialogs/fg1000.xml b/gui/dialogs/fg1000.xml index 9577c33d4..8b45c6460 100644 --- a/gui/dialogs/fg1000.xml +++ b/gui/dialogs/fg1000.xml @@ -15,6 +15,8 @@ var self = cmdarg(); var listeners = []; var mfd = nil; + var eisPublisher = nil; + var navcomPublisher = nil; ]]> @@ -362,8 +369,17 @@ var nasal_dir = getprop("/sim/fg-root") ~ "/Aircraft/Instruments-3d/FG1000/Nasal/"; io.load_nasal(nasal_dir ~ 'MFD.nas', "fg1000"); + io.load_nasal(nasal_dir ~ 'Interfaces/PropertyPublisher.nas', "fg1000"); + io.load_nasal(nasal_dir ~ 'Interfaces/GenericEISPublisher.nas', "fg1000"); + io.load_nasal(nasal_dir ~ 'Interfaces/GenericNavComPublisher.nas', "fg1000"); mfd = fg1000.MFD.new(myCanvas); + eisPublisher = fg1000.GenericEISPublisher.new(); + eisPublisher.start(); + + navcomPublisher = fg1000.GenericNavComPublisher.new(); + navcomPublisher.start(); + softkeypushed = 0; # Connect the buttons - using the provided model index to get the right ones from the model binding var softkey_listener = setlistener("/sim/gui/dialogs/fg1000/softkey-pressed", func(v)