From 7b526adb69b070a81cd91ea605efc071f453911f Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Fri, 16 Mar 2018 15:21:39 +0000 Subject: [PATCH] FG1000 HSI BRG/CDI controls - BRG1/BRG2 now correctly show direction and distance to NAV1/NAV2/GPS/ADF - CDI displays correctly against course, switchable between GPS/NAV1/NAV2 --- .../Nasal/Interfaces/GenericADCPublisher.nas | 3 +- .../Nasal/Interfaces/GenericFMSPublisher.nas | 4 +- .../Interfaces/GenericNavComPublisher.nas | 13 ++ .../Nasal/Interfaces/GenericNavComUpdater.nas | 2 + .../FG1000/Nasal/MFDPageController.nas | 6 +- .../PFDInstruments/PFDInstruments.nas | 164 ++++---------- .../PFDInstrumentsController.nas | 206 +++++++++++++----- .../Nasal/MFDPages/Surround/Surround.nas | 2 +- .../MFDPages/Surround/SurroundController.nas | 53 ++++- 9 files changed, 274 insertions(+), 179 deletions(-) diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericADCPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericADCPublisher.nas index e27e7d165..baca7e3b8 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericADCPublisher.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericADCPublisher.nas @@ -46,7 +46,8 @@ var GenericADCPublisher = obj.addPropMap("ADCSlipSkid", "/instrumentation/slip-skid-ball/indicated-slip-skid"); # Assume an accurate solid-state compass - obj.addPropMap("ADCHeadingDeg", "/orientation/heading-magnetic-deg"); + obj.addPropMap("ADCHeadingMagneticDeg", "/orientation/heading-magnetic-deg"); + obj.addPropMap("ADCMagneticVariationDeg", "/environment/magnetic-variation-deg"); obj.addPropMap("ADCAltitudeFT", "/instrumentation/altimeter/indicated-altitude-ft"); obj.addPropMap("ADCPressureSettingInHG", "/instrumentation/altimeter/setting-inhg"); diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas index f395531dd..ee10cbfc5 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas @@ -31,7 +31,7 @@ var GenericFMSPublisher = 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("FMSLegBearingMagDeg", "/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("FMSLegDesiredTrack", "/instrumentation/gps/wp/wp[1]/desired-course-deg"); @@ -57,7 +57,7 @@ var GenericFMSPublisher = # 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["FMSLegBearingMagDeg"] == -9999) gpsdata["FMSLegBearingMagDeg"] = nil; if (gpsdata["FMSLegDistanceNM"] == -1) gpsdata["FMSLegDistanceNM"] = nil; # A couple of calculated values used by the MFD Header display diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas index fc305b0be..cb99f5bfc 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComPublisher.nas @@ -68,6 +68,13 @@ var GenericNavComPublisher = obj._periodicPublisher.addPropMap("Nav1HeadingDeg", "/instrumentation/nav/heading-deg"); obj._periodicPublisher.addPropMap("Nav1RadialDeg", "/instrumentation/nav/radials/selected-deg"); obj._periodicPublisher.addPropMap("Nav1DistanceMeters", "/instrumentation/nav/nav-distance"); + obj._periodicPublisher.addPropMap("Nav1CourseDeviationDeg", "/instrumentation/nav/crosstrack-heading-error-deg"); + obj._periodicPublisher.addPropMap("Nav1CrosstrackErrorM", "/instrumentation/nav/crosstrack-error-m"); + obj._periodicPublisher.addPropMap("Nav1Localizer", "/instrumentation/nav/nav-loc"); + obj._periodicPublisher.addPropMap("Nav1Deflection", "/instrumentation/nav/heading-needle-deflection-norm"); + obj._periodicPublisher.addPropMap("Nav1From", "/instrumentation/nav/from-flag"); + + obj._triggeredPublisher.addPropMap("Nav1Volume", "/instrumentation/nav/nav-volume"); obj._triggeredPublisher.addPropMap("Nav1AudioID", "/instrumentation/nav/audio-btn"); obj._triggeredPublisher.addPropMap("Nav1Serviceable", "/instrumentation/nav/operable"); @@ -79,6 +86,12 @@ var GenericNavComPublisher = obj._periodicPublisher.addPropMap("Nav2HeadingDeg", "/instrumentation/nav[1]/heading-deg"); obj._periodicPublisher.addPropMap("Nav2RadialDeg", "/instrumentation/nav[1]/radials/selected-deg"); obj._periodicPublisher.addPropMap("Nav2DistanceMeters", "/instrumentation/nav[1]/nav-distance"); + obj._periodicPublisher.addPropMap("Nav2CourseDeviationDeg", "/instrumentation/nav[1]/crosstrack-heading-error-deg"); + obj._periodicPublisher.addPropMap("Nav2CrosstrackErrorM", "/instrumentation/nav[1]/crosstrack-error-m"); + obj._periodicPublisher.addPropMap("Nav2Localizer", "/instrumentation/nav[1]/nav-loc"); + obj._periodicPublisher.addPropMap("Nav2Deflection", "/instrumentation/nav[1]/heading-needle-deflection-norm"); + obj._periodicPublisher.addPropMap("Nav2From", "/instrumentation/nav/from-flag"); + obj._triggeredPublisher.addPropMap("Nav2Volume", "/instrumentation/nav[1]/nav-volume"); obj._triggeredPublisher.addPropMap("Nav2AudioID", "/instrumentation/nav[1]/audio-btn"); obj._triggeredPublisher.addPropMap("Nav2Serviceable", "/instrumentation/nav[1]/operable"); diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComUpdater.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComUpdater.nas index e1b971d93..74d9b9e16 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComUpdater.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericNavComUpdater.nas @@ -55,6 +55,7 @@ var GenericNavComUpdater = obj.addPropMap("Nav1SelectedFreq", "/instrumentation/nav/frequencies/selected-mhz"); obj.addPropMap("Nav1StandbyFreq", "/instrumentation/nav/frequencies/standby-mhz"); obj.addPropMap("Nav1ID", "/instrumentation/nav/nav-id"); + obj.addPropMap("Nav1RadialDeg", "/instrumentation/nav/radials/selected-deg"); obj.addPropMap("Nav1Volume", "/instrumentation/nav/nav-volume"); obj.addPropMap("Nav1AudioID", "/instrumentation/nav/audio-btn"); obj.addPropMap("Nav1Serviceable", "/instrumentation/nav/operable"); @@ -62,6 +63,7 @@ var GenericNavComUpdater = obj.addPropMap("Nav2SelectedFreq", "/instrumentation/nav[1]/frequencies/selected-mhz"); obj.addPropMap("Nav2StandbyFreq", "/instrumentation/nav[1]/frequencies/standby-mhz"); obj.addPropMap("Nav2ID", "/instrumentation/nav[1]/nav-id"); + obj.addPropMap("Nav2RadialDeg", "/instrumentation/nav[1]/radials/selected-deg"); obj.addPropMap("Nav2Volume", "/instrumentation/nav[1]/nav-volume"); obj.addPropMap("Nav2AudioID", "/instrumentation/nav[1]/audio-btn"); obj.addPropMap("Nav2Serviceable", "/instrumentation/nav[1]/operable"); diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas index 554740766..346946db7 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas @@ -45,7 +45,7 @@ handleNavOuter : func (value) { return me.page.mfd.SurroundController.han handleNavInner : func (value) { return me.page.mfd.SurroundController.handleNavInner(value); }, handleNavToggle : func (value) { return me.page.mfd.SurroundController.handleNavToggle(value); }, handleHeading : func (value) { return me.page.mfd.SurroundController.handleHeading(value); }, -handleHeadingPress : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; }, +handleHeadingPress : func (value) { return me.page.mfd.SurroundController.handleHeadingPress(value); }, # Joystick handleRange : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; }, @@ -54,8 +54,8 @@ handleJoystickHorizontal : func (value) { return emesary.Transmitter.ReceiptStat #CRS/BARO handleBaro : func (value) { return me.page.mfd.SurroundController.handleBaro(value); }, -handleCRS : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; }, -handleCRSCenter : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; }, +handleCRS : func (value) { return me.page.mfd.SurroundController.handleCRS(value); }, +handleCRSCenter : func (value) { return me.page.mfd.SurroundController.handleCRSCenter(value); }, handleComOuter : func (value) { return me.page.mfd.SurroundController.handleComOuter(value); }, handleComInner : func (value) { return me.page.mfd.SurroundController.handleComInner(value); }, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas index 4fa4d7e92..3bc4e988a 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas @@ -28,10 +28,6 @@ var PFDInstruments = magenta : [1, 0, 1], }, - CDI_SOURCE : [ "GPS", "NAV1", "NAV2" ], - - BRG_SOURCE : ["OFF", "NAV1", "NAV2", "GPS", "ADF"], - new : func (mfd, myCanvas, device, svg) { var obj = { @@ -42,7 +38,6 @@ var PFDInstruments = _ias_already_exceeded : 0, _windDataDisplay : 0, - _CDISource : "GPS", _BRG1 : "OFF", _BRG2 : "OFF", _DME : 0, @@ -116,7 +111,7 @@ var PFDInstruments = pg.addMenuItem(1, "INSET", pg, pg.mfd.PFDInstruments.insetMenu); pg.addMenuItem(3, "PFD", pg, pg.mfd.PFDInstruments.PFDMenu); pg.addMenuItem(4, "OBS", pg); # TODO - pg.addMenuItem(5, "CDI", pg, pg.incrCDI); + pg.addMenuItem(5, "CDI", pg, func(dev, pg, mi) { pg.getController().incrCDISource(); } ); #pg.addMenuItem(6, "DME", pg, func(dev, pg, mi) { pg.toggleDME(); } ); # TODO pg.addMenuItem(7, "XPDR", pg); # TODO pg.addMenuItem(8, "IDENT", pg); # TODO @@ -126,23 +121,7 @@ var PFDInstruments = 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); @@ -207,9 +186,9 @@ var PFDInstruments = pg.addMenuItem(1, "DFLTS", pg); pg.addMenuItem(2, "WIND", pg, pg.mfd.PFDInstruments.windMenu); #pg.addMenuItem(3, "DME", pg); # TODO - pg.addMenuItem(4, "BRG1", pg, pg.mfd.PFDInstruments.incrBRG1); # TODO + pg.addMenuItem(4, "BRG1", pg, func(dev, pg, mi) { pg.getController().incrBRG1(); }); pg.addMenuItem(5, "HSI FRMT", pg); # TODO - pg.addMenuItem(6, "BRG2", pg, pg.mfd.PFDInstruments.incrBRG2); # TODO + pg.addMenuItem(6, "BRG2", pg, func(dev, pg, mi) { pg.getController().incrBRG2(); }); #pg.addMenuItem(8, "IDENT", pg); # TODO pg.addMenuItem(8, "ALT UNIT ", pg); # TODO pg.addMenuItem(9, "STD BARO", pg, func(dev, pg, mi) { pg.getController().setStdBaro(); } ); @@ -218,29 +197,6 @@ var PFDInstruments = 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) { pg.clearMenu(); pg.resetMenuColors(); @@ -513,31 +469,22 @@ var PFDInstruments = updateCRS : func (crs) { me.getElement("SelectedCRS-text") .setText(sprintf("%03d°%s", crs, "")) - .setColor(me._CDISource == "GPS" ? me.COLORS.magenta : me.COLORS.green); + .setColor(me.getController().getCDISource() == "GPS" ? me.COLORS.magenta : me.COLORS.green); }, updateSelectedALT : func (selected_alt) { me.setTextElement("SelectedALT-text", sprintf("%i", selected_alt)); }, - # Bearing (BRG) settings - # "OFF", "NAV1", "NAV2", "GPS", "ADF" - getBRG1 : func() { return me._BRG1; }, - getBRG2 : func() { return me._BRG2; }, + setBRG1 : func(option) { me._setBRG("BRG1",option); }, + setBRG2 : func(option) { me._setBRG("BRG2",option); }, - setBRG1 : func(option) { - me._BRG1 = option; - me._setBRG("BRG1",option); - }, - setBRG2 : func(option) { - me._BRG2 = option; - me._setBRG("BRG2",option); - }, _setBRG : func (brg, option) { if (option == "OFF") { me.getElement(brg).hide(); me.getElement(brg ~ "-pointer").hide(); - if ((me._BRG1 == "OFF") and (me._BRG2 == "OFF")) { + if ((me.getController().getBRG1() == "OFF") and (me.getController().getBRG2() == "OFF")) { + # Hide the circle if there are now BRGs selected me.getElement("BRG-circle").hide(); } } else { @@ -560,10 +507,10 @@ var PFDInstruments = # Update BRG information updateBRG1 : func(valid, id, dst, current_heading, brg_heading) { - me._updateBRG("BRG1", me._BRG1, valid, id, dst, current_heading, brg_heading); + me._updateBRG("BRG1", me.getController().getBRG1(), valid, id, dst, current_heading, brg_heading); }, updateBRG2 : func(valid, id, dst, current_heading, brg_heading) { - me._updateBRG("BRG2", me._BRG2, valid, id, dst, current_heading, brg_heading); + me._updateBRG("BRG2", me.getController().getBRG2(), valid, id, dst, current_heading, brg_heading); }, _updateBRG : func (brg, source, valid, id, dst, current_heading, brg_heading) { if (source == "OFF") return; @@ -608,74 +555,45 @@ var PFDInstruments = }, setCDISource : func(source) { - if (source == "OFF") { - foreach (var s; ["GPS", "NAV1", "NAV2"]) { - foreach (var t; ["pointer", "CDI", "FROM", "TO"]) { - me.getElement(s ~ "-" ~ t).hide(); - } - } - me.getElement("CDI-GPS-ANN-text").hide(); - me.getElement("CDI-GPS-XTK-text").hide(); - me.getElement("CDI-SRC-text").hide(); - me.getElement("CDI").hide(); - me.getElement("GPS-CTI-diamond").hide(); - me.getElement("SelectedCRS").hide(); - - } else { - me.getElement("CDI").show(); - me.getElement("SelectedCRS").show(); - - if (source == "GPS") { - me.getElement("CDI-GPS-ANN-text").show(); - me.getElement("GPS-CTI-diamond").show(); - } else { - me.getElement("CDI-GPS-ANN-text").hide(); - me.getElement("GPS-CTI-diamond").hide(); - } - - # Localizers are mapped to the NAV1/2 elements, but have reduced deflection - # and a different label. - me.getElement("CDI-SRC-text") - .setText(source) - .setColor(source == "GPS" ? me.COLORS.magenta : me.COLORS.green) - .show(); - - if (source == "LOC1") source = "NAV1"; - if (source == "LOC2") source = "NAV2"; - - foreach (var s; ["GPS", "NAV1", "NAV2"]) { - me.getElement(s ~ "-pointer").setVisible(source == s); - me.getElement(s ~ "-CDI").setVisible(source == s); - me.getElement(s ~ "-FROM").setVisible(source == s); - me.getElement(s ~ "-TO").setVisible(source == s); - } + foreach (var s; ["GPS", "NAV1", "NAV2"]) { + me.getElement(s ~ "-pointer").setVisible(source == s); + me.getElement(s ~ "-CDI").setVisible(source == s); + me.getElement(s ~ "-FROM").setVisible(source == s); + me.getElement(s ~ "-TO").setVisible(source == s); } - me._CDISource = source; + me.getElement("CDI-SRC-text") + .setText(source) + .setColor(source == "GPS" ? me.COLORS.magenta : me.COLORS.green) + .setVisible(source != "OFF"); }, - updateCDI : func (heading, course, waypoint_valid, course_deviation_deg, deflection_dots, xtrk_nm, from, annun) { - if (me._CDISource == "OFF") return; + updateCDI : func (heading, course, waypoint_valid, course_deviation_deg, deflection_dots, xtrk_nm, from, annun, loc) { + + var source = me.getController().getCDISource(); + if (source == "OFF") return; + + # While the user selects between GPS, NAV1, NAV2, we display localizers as LOC1 and LOC2 + if ((source == "NAV1") and (loc == 1)) me.getElement("CDI-SRC-text").setText("LOC1"); + if ((source == "NAV2") and (loc == 1)) me.getElement("CDI-SRC-text").setText("LOC2"); if (waypoint_valid == 0) { - me.getElement(me._CDISource ~ "-CDI").hide(); - me.getElement(me._CDISource ~ "-FROM").hide(); - me.getElement(me._CDISource ~ "-TO").hide(); - me.getElement(me._CDISource ~ "-pointer").hide(); + me.getElement(source ~ "-CDI").hide(); + me.getElement(source ~ "-FROM").hide(); + me.getElement(source ~ "-TO").hide(); + me.getElement(source ~ "-pointer").hide(); me.getElement("CDI").setRotation(0); me.getElement("GPS-CTI-diamond").hide(); me.getElement("CDI-GPS-XTK-text").hide(); - me.getElement("CDI-GPS-ANN-text").hide(); + me.getElement("CDI-GPS-ANN-text").setText("NO DATA").show(); } else { - me.getElement(me._CDISource ~ "-CDI").show(); + me.getElement(source ~ "-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); + me.getElement("GPS-CTI-diamond").setRotation(course_deviation_deg * D2R).setVisible(source == "GPS"); - if ((me._CDISource == "GPS") and (abs(deflection_dots) > 2.0)) { + if ((source == "GPS") and (abs(deflection_dots) > 2.0)) { # Only display the cross-track error if the error exceeds the maximum # deflection of two dots. me.getElement("CDI-GPS-XTK-text") @@ -685,15 +603,19 @@ var PFDInstruments = me.getElement("CDI-GPS-XTK-text").hide(); } - if (me._CDISource == "GPS") me.getElement("CDI-GPS-ANN-text").setText(annun).show(); + if (source == "GPS") { + me.getElement("CDI-GPS-ANN-text").setText(annun).show(); + } else { + me.getElement("CDI-GPS-ANN-text").hide(); + } var scale = math.clamp(deflection_dots, -2.4, 2.4); - me.getElement(me._CDISource ~ "-CDI").setTranslation(80 * scale / 2.4, 0); + me.getElement(source ~ "-CDI").setTranslation(80 * scale / 2.4, 0); # Display the appropriate TO/FROM indication for the selected source, # switching all others off. - me.getElement(me._CDISource ~ "-TO").setVisible(from == 0); - me.getElement(me._CDISource ~ "-FROM").setVisible(from); + me.getElement(source ~ "-TO").setVisible(from == 0); + me.getElement(source ~ "-FROM").setVisible(from); } }, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas index 7731d0cb1..f9254d476 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas @@ -1,3 +1,4 @@ + # Copyright 2018 Stuart Buchanan # This file is part of FlightGear. # @@ -17,6 +18,9 @@ # PFDInstruments Controller var PFDInstrumentsController = { + CDI_SOURCE : [ "GPS", "NAV1", "NAV2" ], + BRG_SOURCE : ["OFF", "NAV1", "NAV2", "GPS", "ADF"], + new : func (page, svg) { var obj = { @@ -24,13 +28,19 @@ var PFDInstrumentsController = _crsrToggle : 0, _pfdrecipient : nil, page : page, + + _CDISource : 0, + _BRG1Source : 0, + _BRG2Source : 0, + _last_ias_kt : 0, _last_alt_ft : 0, _last_trend : systime(), _selected_alt_ft : 0, _heading : 0, - _source : "GPS", - _from :0, + _mag_var : 0, + + _leg_from :0, _leg_id : "", _leg_bearing : 0, _leg_distance_nm : 0, @@ -45,6 +55,11 @@ var PFDInstrumentsController = _nav1_heading_deg :0.0, _nav1_in_range : 0, _nav1_distance_m :0, + _nav1_radial_deg : 0, + _nav1_in_range : 0, + _nav1_distance_m : 0, + _nav1_deviation_deg : 0, + _nav1_loc : 0, _nav2_id : "", _nav2_freq : 0.0, @@ -52,6 +67,11 @@ var PFDInstrumentsController = _nav2_heading_deg : 0.0, _nav2_in_range : 0, _nav2_distance_m :0, + _nav2_radial_deg : 0, + _nav2_in_range : 0, + _nav2_distance_m : 0, + _nav2_deviation_deg : 0, + _nav2_loc : 0, _adf_freq : 0.0, _adf_in_range : 0, @@ -114,6 +134,43 @@ var PFDInstrumentsController = me.transmitter.NotifyAll(notification); }, + incrCDISource : func() { + me._CDISource = math.mod(me._CDISource + 1, size(PFDInstrumentsController.CDI_SOURCE)); + var src = PFDInstrumentsController.CDI_SOURCE[me._CDISource]; + + # If we're changing to NAV1 or NAV2, we also change the selected NAV. + if ((src == "NAV1") or (src == "NAV2")) { + var data = {}; + data["NavSelected"] = (src == "NAV1") ? 1 : 2; + var notification = notifications.PFDEventNotification.new( + "MFD", + me._page.mfd.getDeviceID(), + notifications.PFDEventNotification.NavComData, + data); + + me.transmitter.NotifyAll(notification); + } + + me.page.setCDISource(src); + }, + + getCDISource : func() { + return PFDInstrumentsController.CDI_SOURCE[me._CDISource]; + }, + + incrBRG1 : func() { + me._BRG1Source = math.mod(me._BRG1Source + 1, size(PFDInstrumentsController.BRG_SOURCE)); + me.page.setBRG1(PFDInstrumentsController.BRG_SOURCE[me._BRG1Source]); + }, + + incrBRG2 : func() { + me._BRG2Source = math.mod(me._BRG2Source + 1, size(PFDInstrumentsController.BRG_SOURCE)); + me.page.setBRG2(PFDInstrumentsController.BRG_SOURCE[me._BRG2Source]); + }, + + getBRG1 : func() { return PFDInstrumentsController.BRG_SOURCE[me._BRG1Source]; }, + getBRG2 : func() { return PFDInstrumentsController.BRG_SOURCE[me._BRG2Source]; }, + # Handle update of the airdata information. # ADC data is produced periodically as an entire set handleADCData : func(data) { @@ -139,13 +196,14 @@ var PFDInstrumentsController = me.page.updateBARO(data["ADCPressureSettingInHG"]); me.page.updateOAT(data["ADCOutsideAirTemperatureC"]); - me.page.updateHSI(data["ADCHeadingDeg"]); - me._heading = data["ADCHeadingDeg"]; + me.page.updateHSI(data["ADCHeadingMagneticDeg"]); + me._heading_magnetic_deg = data["ADCHeadingMagneticDeg"]; + me._mag_var = data["ADCMagneticVariationDeg"]; # If we're "flying" at < 10kts, then we won't have sufficient delta between # airspeed and groundspeed to determine wind me.page.updateWindData( - hdg : data["ADCHeadingDeg"], + hdg : data["ADCHeadingMagneticDeg"], wind_hdg : data["ADCWindHeadingDeg"], wind_spd : data ["ADCWindSpeedKt"], no_data: (data["ADCIndicatedAirspeed"] < 1.0) @@ -166,53 +224,56 @@ var PFDInstrumentsController = if (data["FMSLegValid"] != nil) me._leg_valid = data["FMSLegValid"]; - if (me._leg_valid == 0) { - # No valid leg data, likely because there's no GPS course set - me.page.updateCRS(0); - me.page.updateCDI( - heading: me._heading, - course: 0, - waypoint_valid: 0, - course_deviation_deg : 0, - deflection_dots : 0.0, - xtrk_nm : 0, - from: 0, - annun: "NO DATA", - ); + if (me._navSelected == 1) { + if (data["FMSNav1From"] != nil) me._leg_from = data["FMSNav1From"]; } else { + if (data["FMSNav2From"] != nil) me._leg_from = data["FMSNav2From"]; + } - if (data["FMSLegBearing"] != nil) me.page.updateCRS(data["FMSLegBearing"]); + if (data["FMSLegID"] != nil) me._leg_id = data["FMSLegID"]; + if (data["FMSLegBearingMagDeg"] != nil) me._leg_bearing = data["FMSLegBearingMagDeg"]; + if (data["FMSLegDistanceNM"] != nil) me._leg_distance_nm = data["FMSLegDistanceNM"]; + if (data["FMSLegTrackErrorAngle"] != nil) me._leg_deviation_deg = data["FMSLegTrackErrorAngle"]; - if (me._navSelected == 1) { - if (data["FMSNav1From"] != nil) me._from = data["FMSNav1From"]; + # TODO: Proper cross-track error based on source and flight phase. + if (data["FMSLegCourseError"] != nil) me._deflection_dots = data["FMSLegCourseError"] /2.0; + if (data["FMSLegCourseError"] != nil) me._leg_xtrk_nm = data["FMSLegCourseError"]; + + if (me.getCDISource() == "GPS") { + if (me._leg_valid == 0) { + # No valid leg data, likely because there's no GPS course set + me.page.updateCRS(0); + me.page.updateCDI( + heading: me._heading_magnetic_deg, + course: 0, + waypoint_valid: 0, + course_deviation_deg : 0, + deflection_dots : 0.0, + xtrk_nm : 0, + from: 0, + annun: "NO DATA", + loc : 0, + ); } else { - if (data["FMSNav2From"] != nil) me._from = data["FMSNav2From"]; + me.page.updateCRS(me._leg_bearing); + + me.page.updateCDI( + heading: me._heading_magnetic_deg, + course: me._leg_bearing, + waypoint_valid: me._leg_valid, + course_deviation_deg : me._leg_deviation_deg, + deflection_dots : me._deflection_dots, + xtrk_nm : me._leg_xtrk_nm, + from: me._leg_from, + annun: "ENR", + loc: 0, + ); } - - if (data["FMSLegID"] != nil) me._leg_id = data["FMSLegID"]; - if (data["FMSLegBearing"] != nil) me._leg_bearing = data["FMSLegBearing"]; - if (data["FMSLegDistanceNM"] != nil) me._leg_distance_nm = data["FMSLegDistanceNM"]; - 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"] /2.0; - if (data["FMSLegCourseError"] != nil) me._leg_xtrk_nm = data["FMSLegCourseError"]; - - me.page.updateCDI( - heading: me._heading, - course: me._leg_bearing, - waypoint_valid: me._leg_valid, - 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.updateBRG1(me._leg_valid, me._leg_id, me._leg_distance_nm, me._heading, me._leg_bearing); - if (me.page.getBRG2() == "GPS") me.page.updateBRG2(me._leg_valid, me._leg_id, me._leg_distance_nm, me._heading, me._leg_bearing); + if (me.getBRG1() == "GPS") me.page.updateBRG1(me._leg_valid, me._leg_id, me._leg_distance_nm, me._heading_magnetic_deg, me._leg_bearing); + if (me.getBRG2() == "GPS") me.page.updateBRG2(me._leg_valid, me._leg_id, me._leg_distance_nm, me._heading_magnetic_deg, me._leg_bearing); return emesary.Transmitter.ReceiptStatus_OK; }, @@ -229,7 +290,13 @@ var PFDInstrumentsController = if (data["Nav1RadialDeg"] != nil) me._nav1_radial_deg = data["Nav1RadialDeg"]; if (data["Nav1InRange"] != nil) me._nav1_in_range = data["Nav1InRange"]; if (data["Nav1DistanceMeters"] != nil) me._nav1_distance_m = data["Nav1DistanceMeters"]; + if (data["Nav1CourseDeviationDeg"] != nil) me._nav1_deviation_deg = data["Nav1CourseDeviationDeg"]; + # Deflection range is [-10,10], while deflection_dots is [-2.4, 2.4]; + if (data["Nav1Deflection"] != nil) me._nav1_deflection = data["Nav1Deflection"] * 2.4; + if (data["Nav1CrosstrackErrorM"] != nil) me._nav1_crosstrack_m = data["Nav1CrosstrackErrorM"]; + if (data["Nav1From"] != nil) me._nav1_from = data["Nav1From"]; + if (data["Nav1Localizer"] != nil) me._nav1_loc = data["Nav1Localizer"]; if (data["Nav2SelectedFreq"] != nil) me._nav2_freq = data["Nav2SelectedFreq"]; if (data["Nav2ID"] != nil) me._nav2_id = data["Nav2ID"]; @@ -237,18 +304,57 @@ var PFDInstrumentsController = if (data["Nav2RadialDeg"] != nil) me._nav2_radial_deg = data["Nav2RadialDeg"]; if (data["Nav2InRange"] != nil) me._nav2_in_range = data["Nav2InRange"]; if (data["Nav2DistanceMeters"] != nil) me._nav2_distance_m = data["Nav2DistanceMeters"]; + if (data["Nav2CourseDeviationDeg"] != nil) me._nav2_deviation_deg = data["Nav1CourseDeviationDeg"]; + + # Deflection range is [-1,1], while deflection_dots is [-2.4, 2.4]; + if (data["Nav2Deflection"] != nil) me._nav2_deflection = data["Nav2Deflection"] * 2.4; + if (data["Nav2CrosstrackErrorM"] != nil) me._nav2_crosstrack_m = data["Nav2CrosstrackErrorM"]; + if (data["Nav2From"] != nil) me._nav2_from = data["Nav2From"]; + if (data["Nav2Localizer"] != nil) me._nav2_loc = data["Nav2Localizer"]; if (data["ADFSelectedFreq"] != nil) me._adf_freq = data["ADFSelectedFreq"]; if (data["ADFInRange"] != nil) me._adf_in_range = data["ADFInRange"]; if (data["ADFHeadingDeg"] !=nil) me._adf_heading_deg = data["ADFInRange"]; - if (me.page.getBRG1() == "NAV1") me.page.updateBRG1(me._nav1_in_range, me._nav1_id, me._nav1_distance_m * M2NM, me._heading, me._nav1_heading_deg); - if (me.page.getBRG1() == "NAV2") me.page.updateBRG1(me._nav2_in_range, me._nav2_id, me._nav2_distance_m * M2NM, me._heading, me._nav2_heading_deg); - if (me.page.getBRG1() == "ADF") me.page.updateBRG1(me._adf_in_range, sprintf("%.1f", me._adf_freq), 0, me._heading, me._adf_heading_deg); + if (me.getBRG1() == "NAV1") me.page.updateBRG1(me._nav1_in_range, me._nav1_id, me._nav1_distance_m * M2NM, me._heading_magnetic_deg, me._nav1_heading_deg); + if (me.getBRG1() == "NAV2") me.page.updateBRG1(me._nav2_in_range, me._nav2_id, me._nav2_distance_m * M2NM, me._heading_magnetic_deg, me._nav2_heading_deg); + if (me.getBRG1() == "ADF") me.page.updateBRG1(me._adf_in_range, sprintf("%.1f", me._adf_freq), 0, me._heading_magnetic_deg, me._adf_heading_deg); - if (me.page.getBRG2() == "NAV1") me.page.updateBRG2(me._nav1_in_range, me._nav1_id, me._nav1_distance_m * M2NM, me._heading, me._nav1_heading_deg); - if (me.page.getBRG2() == "NAV2") me.page.updateBRG2(me._nav2_in_range, me._nav2_id, me._nav2_distance_m * M2NM, me._heading, me._nav2_heading_deg); - if (me.page.getBRG2() == "ADF") me.page.updateBRG2(me._adf_in_range, sprintf("%.1f", me._adf_freq), 0, me._heading, me._adf_heading_deg); + if (me.getBRG2() == "NAV1") me.page.updateBRG2(me._nav1_in_range, me._nav1_id, me._nav1_distance_m * M2NM, me._heading_magnetic_deg, me._nav1_heading_deg); + if (me.getBRG2() == "NAV2") me.page.updateBRG2(me._nav2_in_range, me._nav2_id, me._nav2_distance_m * M2NM, me._heading_magnetic_deg, me._nav2_heading_deg); + if (me.getBRG2() == "ADF") me.page.updateBRG2(me._adf_in_range, sprintf("%.1f", me._adf_freq), 0, me._heading_magnetic_deg, me._adf_heading_deg); + + if (me.getCDISource() == "NAV1") { + me.page.updateCRS(me._nav1_radial_deg); + me.page.updateCDI( + heading: me._heading_magnetic_deg, + course: me._nav1_radial_deg, + waypoint_valid: me._nav1_in_range, + course_deviation_deg : me._nav1_deviation_deg, + deflection_dots : me._nav1_deflection, + xtrk_nm : me._nav1_crosstrack_m * M2NM, + from: me._nav1_from, + annun: "", + loc : me._nav1_loc, + ); + } + + if (me.getCDISource() == "NAV2") { + me.page.updateCRS(me._nav2_radial_deg); + me.page.updateCDI( + heading: me._heading_magnetic_deg, + course: me._nav2_radial_deg, + waypoint_valid: me._nav2_in_range, + course_deviation_deg : me._nav2_deviation_deg, + deflection_dots : me._nav2_deflection, + xtrk_nm : me._nav2_crosstrack_m * M2NM, + from: me._nav2_from, + annun: "", + loc : me._nav2_loc, + ); + } + + return emesary.Transmitter.ReceiptStatus_OK; }, PFDRegisterWithEmesary : func(transmitter = nil){ diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas index 0d4d66e13..db01e4ea4 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas @@ -57,7 +57,7 @@ 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"}, + "BRG" : { message : "FMSLegBearingMagDeg", format : "%d"}, "XTK" : { message : "FMSLegCourseError", format : "%.1fnm"}, "DIS" : { message : "FMSDistance", format : "%.1fnm"}, "DTK" : { message : "FMSLegDesiredTrack", format : "%d"}, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/SurroundController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/SurroundController.nas index e8f21e3fd..c127a4c17 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/SurroundController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/SurroundController.nas @@ -31,11 +31,16 @@ var SurroundController = _com2standby : 0.0, _nav1active : 0.0, _nav1standby : 0.0, + _nav1radial : 0.0, + _nav1_heading_deg : 0.0, _nav2active : 0.0, _nav2standby : 0.0, + _nav2radial : 0.0, + _nav2_heading_deg : 0.0, _pressure_settings_inhg : 0.0, _selected_alt_ft : 0.0, _heading_bug_deg : 0.0, + _heading_deg : 0.0, }; obj.RegisterWithEmesary(); @@ -81,8 +86,13 @@ var SurroundController = if (data["Nav1SelectedFreq"] != nil) me._nav1active = data["Nav1SelectedFreq"]; if (data["Nav1StandbyFreq"] != nil) me._nav1standby = data["Nav1StandbyFreq"]; + if (data["Nav1RadialDeg"] != nil) me._nav1radial = data["Nav1RadialDeg"]; + if (data["Nav1HeadingDeg"] != nil) me._nav1_heading_deg = data["Nav1HeadingDeg"]; + if (data["Nav2SelectedFreq"] != nil) me._nav2active = data["Nav2SelectedFreq"]; if (data["Nav2StandbyFreq"] != nil) me._nav2standby = data["Nav2StandbyFreq"]; + if (data["Nav2RadialDeg"] != nil) me._nav2radial = data["Nav2RadialDeg"]; + if (data["Nav2HeadingDeg"] != nil) me._nav2_heading_deg = data["Nav2HeadingDeg"]; # pass through to the page me._page.handleNavComData(data); @@ -93,6 +103,7 @@ var SurroundController = 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"]; + if (data["ADCHeadingMagneticDeg"] != nil) me._heading_deg = data["ADCHeadingMagneticDeg"]; # Pass FMS and ADC data straight to the page to display in the header fields me._page.updateHeaderData(data); @@ -211,7 +222,7 @@ var SurroundController = }, # Switch between Nav1 and Nav2. - handleNavToggle : func (value) + handleNavToggle : func () { var data={}; @@ -225,6 +236,13 @@ var SurroundController = return emesary.Transmitter.ReceiptStatus_Finished; }, + setNav : func(value) { + var data={}; + data["NavSelected"] = value; + me.sendNavComDataNotification(data); + return emesary.Transmitter.ReceiptStatus_Finished; + }, + # Outer COM dial changes the integer value of the standby selected COM # frequency, wrapping on limits. Leaves the fractional part unchanged handleComOuter : func (value) { @@ -366,6 +384,32 @@ var SurroundController = return emesary.Transmitter.ReceiptStatus_Finished; }, + handleCRS : func(value) { + var incr_or_decr = (value > 0) ? 1 : -1; + var data={}; + + if (me._navselected == 1) { + data["Nav1RadialDeg"] = math.mod(me._nav1radial + incr_or_decr, 360); + } else { + data["Nav2RadialDeg"] = math.mod(me._nav2radial + incr_or_decr, 360); + } + + me.sendNavComDataNotification(data); + return emesary.Transmitter.ReceiptStatus_Finished; + }, + + handleCRSCenter : func(value) { + var data = {}; + if (me._navselected == 1) { + data["Nav1RadialDeg"] = me._nav1_heading_deg; + } else { + data["Nav2RadialDeg"] = me._nav2_heading_deg; + } + + me.sendNavComDataNotification(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); @@ -396,6 +440,13 @@ var SurroundController = return emesary.Transmitter.ReceiptStatus_Finished; }, + handleHeadingPress : func(value) { + var data = {}; + data["FMSHeadingBug"] = me._heading_deg; + me.sendFMSDataNotification(data); + return emesary.Transmitter.ReceiptStatus_Finished; + }, + # 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.