From 8bbe755c7c5dce28b7118d479714ebff0ea4e049 Mon Sep 17 00:00:00 2001 From: Jonathan Redpath Date: Mon, 16 May 2022 17:13:14 +0100 Subject: [PATCH] Handle MANUAL legs properly --- Nasal/FMGC/flightplan-delegates.nas | 130 ++++++++++++++++++++++++++-- Nasal/FMGC/flightplan.nas | 7 +- Nasal/Libraries/libraries.nas | 2 +- Nasal/MCDU/F-PLN.nas | 14 +-- 4 files changed, 139 insertions(+), 14 deletions(-) diff --git a/Nasal/FMGC/flightplan-delegates.nas b/Nasal/FMGC/flightplan-delegates.nas index 50859277..4938c00b 100644 --- a/Nasal/FMGC/flightplan-delegates.nas +++ b/Nasal/FMGC/flightplan-delegates.nas @@ -20,6 +20,127 @@ # You can disable the default GPS behaviour *without* touching this delegate : they are # kept seperate since this first one is less likely to need changes + +var A320RouteManagerDelegate = { + new: func(fp) { + var m = { parents: [A320RouteManagerDelegate] }; + + logprint(LOG_INFO, 'creating A320 Route Manager FPDelegate'); + + m.flightplan = fp; + return m; + }, + + departureChanged: func + { + logprint(LOG_INFO, 'saw departure changed'); + me.flightplan.clearWPType('sid'); + if (me.flightplan.departure == nil) + return; + + if (me.flightplan.departure_runway == nil) { + # no runway, only an airport, use that + var wp = createWPFrom(me.flightplan.departure); + wp.wp_role = 'sid'; + me.flightplan.insertWP(wp, 0); + return; + } + # first, insert the runway itself + var wp = createWPFrom(me.flightplan.departure_runway); + wp.wp_role = 'sid'; + me.flightplan.insertWP(wp, 0); + if (me.flightplan.sid == nil) + return; + + # and we have a SID + var sid = me.flightplan.sid; + logprint(LOG_INFO, 'routing via SID ' ~ sid.id); + me.flightplan.insertWaypoints(sid.route(me.flightplan.departure_runway, me.flightplan.sid_trans), 1); + + for (var wpIdx = 0; wpIdx < me.flightplan.getPlanSize(); wpIdx = wpIdx + 1) { + if (me.flightplan.getWP(wpIdx).wp_type == "vectors" and (me.flightplan.getWP(wpIdx + 1) == nil or me.flightplan.getWP(wpIdx + 1).wp_type != "discontinuity")) { + me.flightplan.insertWP(createDiscontinuity(), wpIdx + 1); + } + } + }, + + arrivalChanged: func + { + me.flightplan.clearWPType('star'); + me.flightplan.clearWPType('approach'); + if (me.flightplan.destination == nil) + return; + + if (me.flightplan.destination_runway == nil) { + # no runway, only an airport, use that + var wp = createWPFrom(me.flightplan.destination); + wp.wp_role = 'approach'; + me.flightplan.appendWP(wp); + return; + } + + var initialApproachFix = nil; + if (me.flightplan.star != nil) { + logprint(LOG_INFO, 'routing via STAR ' ~ me.flightplan.star.id); + var wps = me.flightplan.star.route(me.flightplan.destination_runway, me.flightplan.star_trans); + if (wps != nil) { + me.flightplan.insertWaypoints(wps, -1); + initialApproachFix = wps[-1]; # final waypoint of STAR + } + } + + if (me.flightplan.approach != nil) { + var wps = nil; + var approachIdent = me.flightplan.approach.id; + + if (me.flightplan.approach_trans != nil) { + # if an approach transition was specified, let's use it explicitly + wps = me.flightplan.approach.route(me.flightplan.destination_runway, me.flightplan.approach_trans); + if (wps == nil) { + logprint(LOG_WARN, "couldn't route approach " ~ approachIdent ~ " based on specified transition:" ~ me.flightplan.approach_trans); + } + } else if (initialApproachFix != nil) { + # no explicit approach transition, let's use the IAF to guess one + wps = me.flightplan.approach.route(me.flightplan.destination_runway, initialApproachFix); + if (wps == nil) { + logprint(LOG_INFO, "couldn't route approach " ~ approachIdent ~ " based on IAF:" ~ initialApproachFix.wp_name); + } + } + + # depending on the order the user selects the approach or STAR, we might get into + # a mess here. If we failed to route so far, just try a direct to the approach + if (wps == nil) { + # route direct + wps = me.flightplan.approach.route(me.flightplan.destination_runway); + } + + if (wps == nil) { + logprint(LOG_WARN, 'routing via approach ' ~ approachIdent ~ ' failed entirely.'); + } else { + me.flightplan.insertWaypoints(wps, -1); + } + } else { + # no approach, just use the runway waypoint + var wp = createWPFrom(me.flightplan.destination_runway); + wp.wp_role = 'approach'; + me.flightplan.appendWP(wp); + } + }, + + cleared: func + { + logprint(LOG_INFO, "saw active flightplan cleared, deactivating"); + # see http://https://code.google.com/p/flightgear-bugs/issues/detail?id=885 + fgcommand("activate-flightplan", props.Node.new({"activate": 0})); + }, + + endOfFlightPlan: func + { + logprint(LOG_INFO, "end of flight-plan, deactivating"); + fgcommand("activate-flightplan", props.Node.new({"activate": 0})); + } +}; + var GPSPath = "/instrumentation/gps"; # this delegate corresponds to the default behaviour of the built-in GPS. @@ -129,13 +250,7 @@ var A320GPSDelegate = { if (me.flightplan.current + 1 >= me.flightplan.numWaypoints()) { logprint(LOG_INFO, "default GPS sequencing, finishing flightplan"); me.flightplan.finish(); - } elsif (me.flightplan.nextWP().wp_type == 'discontinuity') { - logprint(LOG_INFO, "default GPS sequencing DISCONTINUITY in flightplan, switching to HDG"); - - me._captureCurrentCourse(); - me._selectOBSMode(); - # set HDG mode - } else { + } elsif (me.flightplan.nextWP().wp_type != 'discontinuity' and me.flightplan.nextWP().wp_type != 'vectors') { logprint(LOG_INFO, "default GPS sequencing to next WP"); me.flightplan.current = me.flightplan.current + 1; } @@ -173,4 +288,5 @@ var A320GPSDelegate = { }; registerFlightPlanDelegate(A320GPSDelegate.new); +registerFlightPlanDelegate(A320RouteManagerDelegate.new); diff --git a/Nasal/FMGC/flightplan.nas b/Nasal/FMGC/flightplan.nas index 9fcc9309..f8d39444 100644 --- a/Nasal/FMGC/flightplan.nas +++ b/Nasal/FMGC/flightplan.nas @@ -229,6 +229,11 @@ var flightPlanController = { if (me.flightplans[2].getWP(me.currentToWptIndexTemp + 1).wp_type == "discontinuity") { fmgc.Input.lat.setValue(3); } else { + if (me.flightplans[2].getWP(me.currentToWptIndexTemp + 1).wp_type == "vectors") { + fmgc.Input.lat.setValue(3); + me.flightplans[2].deleteWP(me.currentToWptIndexTemp + 2); + } + me.currentToWptIndex.setValue(me.currentToWptIndexTemp + 1); me.lastSequencedCurrentWP = me.currentToWptIndexTemp + 1; @@ -408,7 +413,7 @@ var flightPlanController = { } } } else { - if (me.flightplans[n].getWP(index).id == "DISCONTINUITY" and index > 0 and me.flightplans[n].getWP(index - 1).id == "PPOS") { + if (me.flightplans[n].getWP(index).id == "DISCONTINUITY" and index > 0 and (me.flightplans[n].getWP(index - 1).id == "PPOS" or find(me.flightplans[n].getWP(index - 1).id, "VECTORS"))) { return 1; } else { me.flightplans[n].deleteWP(index); diff --git a/Nasal/Libraries/libraries.nas b/Nasal/Libraries/libraries.nas index 3fe23fac..ca600559 100644 --- a/Nasal/Libraries/libraries.nas +++ b/Nasal/Libraries/libraries.nas @@ -7,7 +7,7 @@ print("------------------------------------------------"); print("Copyright (c) 2016-2020 Josh Davidson (Octal450)"); print("------------------------------------------------"); -# setprop("/autopilot/route-manager/disable-route-manager", 1); +setprop("/autopilot/route-manager/disable-route-manager", 1); setprop("/autopilot/route-manager/disable-fms", 1); # Disable specific menubar items diff --git a/Nasal/MCDU/F-PLN.nas b/Nasal/MCDU/F-PLN.nas index 5ec16f8c..9b4d898d 100644 --- a/Nasal/MCDU/F-PLN.nas +++ b/Nasal/MCDU/F-PLN.nas @@ -120,10 +120,14 @@ var fplnItem = { }, getBrg: func() { var wp = fmgc.flightPlanController.flightplans[me.plan].getWP(me.index); - var courseDistanceFrom = courseAndDistance(wp); - me.brg = courseDistanceFrom[0] - magvar(); - if (me.brg < 0) { me.brg += 360; } - if (me.brg > 360) { me.brg -= 360; } + if (wp.wp_type == "vectors") { + me.brg = pts.Orientation.heading.getValue(); + } else { + var courseDistanceFrom = courseAndDistance(wp); + me.brg = courseDistanceFrom[0] - magvar(); + if (me.brg < 0) { me.brg += 360; } + if (me.brg > 360) { me.brg -= 360; } + } return sprintf("%03.0f", math.round(me.brg)); }, getTrack: func() { @@ -174,7 +178,7 @@ var fplnItem = { } else { if (me.plan == 2 and decelShow and me.index == decelIndex and fmgc.flightPlanController.decelPoint != nil) { return sprintf("%3.0f", courseAndDistance(fmgc.flightPlanController.decelPoint, me.wp)[1]); - } else if (prevwp != nil and prevwp.wp_name != "DISCONTINUITY") { + } else if (prevwp != nil and (prevwp.wp_name != "DISCONTINUITY" or find(prevwp.wp_name, "VECTORS"))) { return sprintf("%3.0f", math.round(me.wp.leg_distance)); } else { return " --";