From b64dd768d36c1345776244b197026a2a3a7deb12 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 7 Apr 2013 21:45:29 +0100 Subject: [PATCH] Move more high-level GPS logic to Nasal/XML. --- Nasal/route_manager.nas | 69 +++++++++++++++++++++++++++++------ gui/dialogs/gps.xml | 62 ++++++++++++++++++++----------- gui/dialogs/route-manager.xml | 33 ++++++++++++++++- 3 files changed, 129 insertions(+), 35 deletions(-) diff --git a/Nasal/route_manager.nas b/Nasal/route_manager.nas index 92b860065..a3f1e2a3e 100644 --- a/Nasal/route_manager.nas +++ b/Nasal/route_manager.nas @@ -1,13 +1,13 @@ -# route_manager.nas - default FlightPlan delegate corresponding to the build -# in route-manager dialog. Intended to provide a sensible default behaviour, -# but be disabled by an aircraft-specific FMS / GPS system. +# route_manager.nas - FlightPlan delegate(s) corresponding to the built- +# in route-manager dialog and GPS. Intended to provide a sensible default behaviour, +# but can be disabled by an aircraft-specific FMS / GPS system. var RouteManagerDelegate = { new: func(fp) { - # if this property is set, don't build a delegate at all - if (getprop('/autopilot/route-manager/disable-fms')) - return nil; - + # if this property is set, don't build a delegate at all + if (getprop('/autopilot/route-manager/disable-route-manager')) + return nil; + var m = { parents: [RouteManagerDelegate] }; m.flightplan = fp; return m; @@ -86,19 +86,66 @@ var RouteManagerDelegate = { { debug.dump("end of flight-plan, deactivating"); fgcommand("activate-flightplan", props.Node.new({"activate": 0})); - }, + } +}; + + +var FMSDelegate = { + new: func(fp) { + # if this property is set, don't build a delegate at all + if (getprop('/autopilot/route-manager/disable-fms')) + return nil; + + var m = { parents: [FMSDelegate], flightplan:fp, landingCheck:nil }; + return m; + }, + + _landingCheckTimeout: func + { + var cur = me.flightplan.currentWP(); + var wow = getprop('gear/gear[0]/wow'); + var gs = getprop('velocities/groundspeed-kt'); + if (wow and (gs < 25)) { + debug.dump('touchdown on destination runway, end of route.'); + me.landingCheck.stop(); + # record touch-down time? + me.flightplan.finish(); + } + }, waypointsChanged: func { }, + endOfFlightPlan: func + { + debug.dump('end of flight-plan'); + }, + currentWaypointChanged: func { - debug.dump('saw current WP changed, now ' ~ me.flightplan.current); + if (me.landingCheck != nil) { + me.landingCheck.stop(); + me.landingCheck = nil; # delete timer + } + + #debug.dump('saw current WP changed, now ' ~ me.flightplan.current); + var active = me.flightplan.currentWP(); + if (active == nil) return; + + if (active.alt_cstr_type != 'none') { + debug.dump('new WP has valid altitude restriction, setting on AP'); + setprop('/autopilot/settings/target-altitude-ft', active.alt_cstr); + } + + var activeRunway = active.runway(); + if ((activeRunway != nil) and (activeRunway.id == me.flightplan.destination_runway.id)) { + me.landingCheck = maketimer(2.0, me, FMSDelegate._landingCheckTimeout); + me.landingCheck.start(); + } } }; -# debug.dump('register routemanager delegate factory'); - +registerFlightPlanDelegate(FMSDelegate.new); registerFlightPlanDelegate(RouteManagerDelegate.new); diff --git a/gui/dialogs/gps.xml b/gui/dialogs/gps.xml index 62c9f7092..73d99691b 100644 --- a/gui/dialogs/gps.xml +++ b/gui/dialogs/gps.xml @@ -11,14 +11,17 @@ var cmd = gps.getNode("command", 1); var scratch = gps.getNode("scratch", 1); var scratchValid = scratch.getNode("valid", 1); - - var updateSearchResults = func - { - debug.dump('search results is:', searchResults); + var searchIsWaypoints = 0; + var anySpec = 'vor,airport,heliport,ils,seaport,fix,ndb,waypoint,tacan,city,town'; - dlg.getNode("scratch-index", 1).setValue(0); - dlg.getNode("scratch-has-next", 1).setBoolValue(size(searchResults) > 1); + var updateSearchResults = func(isWpts, index = 0) + { + searchIsWaypoints = isWpts; + dlg.getNode("scratch-index", 1).setValue(index); + var lastIndex = size(searchResults) - 1; + dlg.getNode("scratch-has-next", 1).setValue((index + 1) < lastIndex); + if (size(searchResults) < 1) { scratchValid.setBoolValue(0); return; @@ -34,23 +37,33 @@ scratchValid.setBoolValue(0); return; } - - var ty = result.type; + scratchValid.setBoolValue(1); - scratch.getNode("type", 1).setValue(ty); scratch.getNode("latitude-deg", 1).setValue(result.lat); scratch.getNode("longitude-deg", 1).setValue(result.lon); - scratch.getNode("altitude-ft", 1).setValue(result.elevation); scratch.getNode("ident", 1).setValue(result.id); - scratch.getNode("name", 1).setValue(result.name); + var cd = nil; - if (ty == 'vor') { - scratch.getNode("frequency-mhz", 1).setValue(result.frequency); - } elsif (ty == 'ndb') { - scratch.getNode("frequency-khz", 1).setValue(result.frequency); + if (searchIsWaypoints) { + scratch.getNode("type", 1).setValue('WPT'); + + cd = result.courseAndDistanceFrom(geo.aircraft_position()); + } else { + var ty = result.type; + scratch.getNode("type", 1).setValue(ty); + scratch.getNode("name", 1).setValue(result.name); + scratch.getNode("altitude-ft", 1).setValue(result.elevation); + + if (ty == 'vor') { + scratch.getNode("frequency-mhz", 1).setValue(result.frequency); + } elsif (ty == 'ndb') { + scratch.getNode("frequency-khz", 1).setValue(result.frequency); + } + + cd = positioned.courseAndDistance(result); } - - var cd = positioned.courseAndDistance(result); + + scratch.getNode("mag-bearing-deg", 1).setValue(cd[0] + magvar()); scratch.getNode("distance-nm", 1).setValue(cd[1]); @@ -60,24 +73,27 @@ var doSearch = func() { var ty = dlg.getNode("search-type").getValue(); + if (ty == 'any') ty = anySpec; + var query = dlg.getNode("search-query").getValue(); searchResults = positioned.sortByRange(positioned.findByIdent(query, ty)); - updateSearchResults(); + updateSearchResults(0); } var doSearchNames = func { var ty = dlg.getNode("search-type").getValue(); + if (ty == 'any') ty = anySpec; var query = dlg.getNode("search-query").getValue(); searchResults = positioned.sortByRange(positioned.findByName(query, ty)); - updateSearchResults(); + updateSearchResults(0); } var doSearchNearest = func { var ty = dlg.getNode("search-type").getValue(); searchResults = positioned.findWithinRange(200.0, ty); - updateSearchResults(); + updateSearchResults(0); } var doLoadRouteWaypoint = func @@ -87,7 +103,7 @@ for (var i=0; i < fp.getPlanSize(); i+=1) { append(searchResults, fp.getWP(i)); } - updateSearchResults(); + updateSearchResults(1, fp.current); } var doScratchPrevious = func @@ -111,7 +127,7 @@ } var searchResults = []; - updateSearchResults(); + updateSearchResults(0); var slaved = props.globals.getNode("/instrumentation/nav[0]/slaved-to-gps", 1); ]]> @@ -399,6 +415,8 @@ ndb fix wpt + city + town true dialog-apply diff --git a/gui/dialogs/route-manager.xml b/gui/dialogs/route-manager.xml index 1781c7471..1b72bb38e 100644 --- a/gui/dialogs/route-manager.xml +++ b/gui/dialogs/route-manager.xml @@ -224,9 +224,38 @@ command interface /autopilot/route-manager/input: gui.dialog_update("route-manager", "approach"); } - + var initPosition = func { + var routeActive = routem.getNode("active").getValue(); + if (routeActive) return; + + # FIXME have user waypoints check + var fp = flightplan(); + + var airborne = getprop('/gear/gear[0]/wow') == 0; + if (airborne) { + debug.dump('route-manager dialog, init in-air, clearing departure settings'); + fp.departure = nil; + return; + } + + + + # we're on the ground, find the nearest airport to start from + if (fp.departure == nil) { + var apts = findAirportsWithinRange(25.0); + if (size(apts) == 0) return; # no airports nearby + fp.departure = apts[0]; # use the closest one + } + + if (fp.departure_runway == nil) { + debug.dump('selecting departure runway'); + var rwy = fp.departure.findBestRunwayForPos( geo.aircraft_position() ); + fp.departure_runway = rwy; + } + } + # initialise departure values based on current position - cmd.setValue("@posinit"); + initPosition(); updateRunways(); updateSIDs();