]> git.mxchange.org Git - flightgear.git/blobdiff - src/Instrumentation/gps.cxx
Support for multiple data dirs.
[flightgear.git] / src / Instrumentation / gps.cxx
index 3d15e8e57a11a4ef4c5e1179483795772cabae54..700b2aab111015fd74758f6e9b07a53ad7330378 100644 (file)
@@ -14,6 +14,7 @@
 #include <memory>
 #include <set>
 #include <cstring>
+#include <cstdio>
 
 #include "Main/fg_props.hxx"
 #include "Main/globals.hxx" // for get_subsystem
@@ -21,7 +22,8 @@
 #include "Navaids/positioned.hxx"
 #include <Navaids/waypoint.hxx>
 #include "Navaids/navrecord.hxx"
-#include "Airports/simple.hxx"
+#include "Navaids/FlightPlan.hxx"
+#include "Airports/airport.hxx"
 #include "Airports/runways.hxx"
 #include "Autopilot/route_mgr.hxx"
 
 #include <simgear/sg_inlines.h>
 #include <simgear/math/sg_geodesy.hxx>
 #include <simgear/structure/exception.hxx>
-#include <simgear/scene/util/OsgMath.hxx>
 
 using std::auto_ptr;
 using std::string;
 using namespace flightgear;
 
-///////////////////////////////////////////////////////////////////
-
-void SGGeodProperty::init(SGPropertyNode* base, const char* lonStr, const char* latStr, const char* altStr)
-{
-    _lon = base->getChild(lonStr, 0, true);
-    _lat = base->getChild(latStr, 0, true);
-    if (altStr) {
-        _alt = base->getChild(altStr, 0, true);
-    }
-}
-
-void SGGeodProperty::init(const char* lonStr, const char* latStr, const char* altStr)
-{
-    _lon = fgGetNode(lonStr, true);
-    _lat = fgGetNode(latStr, true);
-    if (altStr) {
-        _alt = fgGetNode(altStr, true);
-    }
-}
-
-void SGGeodProperty::clear()
-{
-    _lon = _lat = _alt = NULL;
-}
-
-void SGGeodProperty::operator=(const SGGeod& geod)
-{
-    _lon->setDoubleValue(geod.getLongitudeDeg());
-    _lat->setDoubleValue(geod.getLatitudeDeg());
-    if (_alt) {
-        _alt->setDoubleValue(geod.getElevationFt());
-    }
-}
-
-SGGeod SGGeodProperty::get() const
-{
-    double lon = _lon->getDoubleValue(),
-        lat = _lat->getDoubleValue();
-        
-    if (osg::isNaN(lon) || osg::isNaN(lat)) {
-      SG_LOG(SG_INSTR, SG_WARN, "read NaN for lon/lat:" << _lon->getPath() 
-        << ", " << _lat->getPath());
-      return SGGeod();
-    }
-        
-    if (_alt) {
-        return SGGeod::fromDegFt(lon, lat, _alt->getDoubleValue());
-    } else {
-        return SGGeod::fromDeg(lon,lat);
-    }
-}
 
 static const char* makeTTWString(double TTW)
 {
@@ -105,94 +55,6 @@ static const char* makeTTWString(double TTW)
   return TTW_str;
 }
 
-/////////////////////////////////////////////////////////////////////////////
-
-class GPSListener : public SGPropertyChangeListener
-{
-public:
-  GPSListener(GPS *m) : 
-    _gps(m),
-    _guard(false) {}
-    
-  virtual void valueChanged (SGPropertyNode * prop)
-  {
-    if (_guard) {
-      return;
-    }
-    
-    _guard = true;
-    if (prop == _gps->_route_current_wp_node) {
-      _gps->routeManagerSequenced();
-    } else if (prop == _gps->_route_active_node) {
-      _gps->routeActivated();
-    } else if (prop == _gps->_ref_navaid_id_node) {
-      _gps->referenceNavaidSet(prop->getStringValue(""));
-    } else if (prop == _gps->_routeEditedSignal) {
-      _gps->routeEdited();
-    } else if (prop == _gps->_routeFinishedSignal) {
-      _gps->routeFinished();
-    }
-        
-    _guard = false;
-  }
-  
-  void setGuard(bool g) {
-    _guard = g;
-  }
-private:
-  GPS* _gps;
-  bool _guard; // re-entrancy guard
-};
-
-////////////////////////////////////////////////////////////////////////////
-/**
- * Helper to monitor for Nasal or other code accessing properties we haven't
- * defined. For the moment we complain about all such activites, since various
- * users assume all kinds of weird, wonderful and non-existent interfaces.
- */
-class DeprecatedPropListener : public SGPropertyChangeListener
-{
-public:
-  DeprecatedPropListener(SGPropertyNode* gps)
-  {
-    _parents.insert(gps);
-    SGPropertyNode* wp = gps->getChild("wp", 0, true); 
-    _parents.insert(wp);
-    _parents.insert(wp->getChild("wp", 0, true));
-    _parents.insert(wp->getChild("wp", 1, true));
-    
-    std::set<SGPropertyNode*>::iterator it;
-    for (it = _parents.begin(); it != _parents.end(); ++it) {
-      (*it)->addChangeListener(this);
-    }
-  }
-  
-  virtual void valueChanged (SGPropertyNode * prop)
-  {
-  }
-  
-  virtual void childAdded (SGPropertyNode * parent, SGPropertyNode * child)
-  {
-    if (isDeprecated(parent, child)) {
-      SG_LOG(SG_INSTR, SG_WARN, "GPS: someone accessed a deprecated property:"
-        << child->getPath(true));
-    }
-  }
-private:
-  bool isDeprecated(SGPropertyNode * parent, SGPropertyNode * child) const 
-  {
-    if (_parents.count(parent) < 1) {
-      return false;
-    }
-    
-    // no child exclusions yet
-    return true;
-  }
-  
-  std::set<SGPropertyNode*> _parents;
-};
-
 ////////////////////////////////////////////////////////////////////////////
 // configuration helper object
 
@@ -222,22 +84,22 @@ void GPS::Config::bind(GPS* aOwner, SGPropertyNode* aCfg)
 
 ////////////////////////////////////////////////////////////////////////////
 
-GPS::GPS ( SGPropertyNode *node) : 
+GPS::GPS ( SGPropertyNode *node, bool defaultGPSMode) :
   _selectedCourse(0.0),
   _desiredCourse(0.0),
   _dataValid(false),
   _lastPosValid(false),
+  _defaultGPSMode(defaultGPSMode),
   _mode("init"),
   _name(node->getStringValue("name", "gps")),
   _num(node->getIntValue("number", 0)),
-  _searchResultIndex(0),
-  _searchExact(true),
-  _searchIsRoute(false),
-  _searchHasNext(false),
-  _searchNames(false),
   _computeTurnData(false),
   _anticipateTurn(false),
-  _inTurn(false)
+  _inTurn(false),
+  _callbackFlightPlanChanged(SGPropertyChangeCallback<GPS>(this,&GPS::routeManagerFlightPlanChanged,
+                                                           fgGetNode("/autopilot/route-manager/signals/flightplan-changed", true))),
+  _callbackRouteActivated(SGPropertyChangeCallback<GPS>(this,&GPS::routeActivated,
+                                                      fgGetNode("/autopilot/route-manager/active", true)))
 {
   string branch = "/instrumentation/" + _name;
   _gpsNode = fgGetNode(branch.c_str(), _num, true );
@@ -245,6 +107,12 @@ GPS::GPS ( SGPropertyNode *node) :
   
   SGPropertyNode *wp_node = _gpsNode->getChild("wp", 0, true);
   _currentWayptNode = wp_node->getChild("wp", 1, true);
+    
+#if FG_210_COMPAT
+    _searchIsRoute = false;
+    _searchHasNext = false;
+    _searchType = FGPositioned::INVALID;
+#endif
 }
 
 GPS::~GPS ()
@@ -254,10 +122,6 @@ GPS::~GPS ()
 void
 GPS::init ()
 {
-  _routeMgr = (FGRouteMgr*) globals->get_subsystem("route-manager");
-  assert(_routeMgr);
-  
-  _position.init("/position/longitude-deg", "/position/latitude-deg", "/position/altitude-ft");
   _magvar_node = fgGetNode("/environment/magnetic-variation-deg", true);
   _serviceable_node = _gpsNode->getChild("serviceable", 0, true);
   _serviceable_node->setBoolValue(true);
@@ -278,36 +142,14 @@ GPS::init ()
   wp1Crs->alias(_gpsNode->getChild("desired-course-deg", 0, true));
 
   _tracking_bug_node = _gpsNode->getChild("tracking-bug", 0, true);
-         
-// reference navid
-  SGPropertyNode_ptr ref_navaid = _gpsNode->getChild("ref-navaid", 0, true);
-  _ref_navaid_id_node = ref_navaid->getChild("id", 0, true);
-  _ref_navaid_name_node = ref_navaid->getChild("name", 0, true);
-  _ref_navaid_bearing_node = ref_navaid->getChild("bearing-deg", 0, true);
-  _ref_navaid_frequency_node = ref_navaid->getChild("frequency-mhz", 0, true);
-  _ref_navaid_distance_node = ref_navaid->getChild("distance-nm", 0, true);
-  _ref_navaid_mag_bearing_node = ref_navaid->getChild("mag-bearing-deg", 0, true);
-  _ref_navaid_elapsed = 0.0;
-  _ref_navaid_set = false;
     
-// route properties    
+// route properties
   // should these move to the route manager?
   _routeDistanceNm = _gpsNode->getChild("route-distance-nm", 0, true);
   _routeETE = _gpsNode->getChild("ETE", 0, true);
-  _routeEditedSignal = fgGetNode("/autopilot/route-manager/signals/edited", true);
-  _routeFinishedSignal = fgGetNode("/autopilot/route-manager/signals/finished", true);
-  
-// add listener to various things
-  _listener = new GPSListener(this);
-  _route_current_wp_node = fgGetNode("/autopilot/route-manager/current-wp", true);
-  _route_current_wp_node->addChangeListener(_listener);
-  _route_active_node = fgGetNode("/autopilot/route-manager/active", true);
-  _route_active_node->addChangeListener(_listener);
-  _ref_navaid_id_node->addChangeListener(_listener);
-  _routeEditedSignal->addChangeListener(_listener);
-  _routeFinishedSignal->addChangeListener(_listener);
-  
-// navradio slaving properties  
+
+    
+// navradio slaving properties
   SGPropertyNode* toFlag = _gpsNode->getChild("to-flag", 0, true);
   toFlag->alias(_currentWayptNode->getChild("to-flag"));
   
@@ -317,18 +159,13 @@ GPS::init ()
 // autopilot drive properties
   _apDrivingFlag = fgGetNode("/autopilot/settings/gps-driving-true-heading", true);
   _apTrueHeading = fgGetNode("/autopilot/settings/true-heading-deg",true);
-  _apTargetAltitudeFt = fgGetNode("/autopilot/settings/target-altitude-ft", true);
-  _apAltitudeLock = fgGetNode("/autopilot/locks/altitude", true);
-  
-// realism prop[s]
-  _realismSimpleGps = fgGetNode("/sim/realism/simple-gps", true);
-  if (!_realismSimpleGps->hasValue()) {
-    _realismSimpleGps->setBoolValue(true);
-  }
-  
-  // last thing, add the deprecated prop watcher
-  new DeprecatedPropListener(_gpsNode);
-  
+    
+  clearOutput();
+}
+
+void
+GPS::reinit ()
+{
   clearOutput();
 }
 
@@ -360,20 +197,27 @@ GPS::bind()
 // command system
   tie(_gpsNode, "mode", SGRawValueMethods<GPS, const char*>(*this, &GPS::getMode, NULL));
   tie(_gpsNode, "command", SGRawValueMethods<GPS, const char*>(*this, &GPS::getCommand, &GPS::setCommand));
-    
   tieSGGeod(_scratchNode, _scratchPos, "longitude-deg", "latitude-deg", "altitude-ft");
-  tie(_scratchNode, "valid", SGRawValueMethods<GPS, bool>(*this, &GPS::getScratchValid, NULL));
-  tie(_scratchNode, "distance-nm", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchDistance, NULL));
-  tie(_scratchNode, "true-bearing-deg", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchTrueBearing, NULL));
-  tie(_scratchNode, "mag-bearing-deg", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchMagBearing, NULL));
-  tie(_scratchNode, "has-next", SGRawValueMethods<GPS, bool>(*this, &GPS::getScratchHasNext, NULL));
-  _scratchValid = false;
-
   
+#if FG_210_COMPAT
+    tie(_scratchNode, "valid", SGRawValueMethods<GPS, bool>(*this, &GPS::getScratchValid, NULL));
+    tie(_scratchNode, "distance-nm", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchDistance, NULL));
+    tie(_scratchNode, "true-bearing-deg", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchTrueBearing, NULL));
+    tie(_scratchNode, "mag-bearing-deg", SGRawValueMethods<GPS, double>(*this, &GPS::getScratchMagBearing, NULL));
+    tie(_scratchNode, "has-next", SGRawValueMethods<GPS, bool>(*this, &GPS::getScratchHasNext, NULL));
+    _scratchValid = false;
+    
+    _scratchNode->setStringValue("type", "");
+    _scratchNode->setStringValue("query", "");
+#endif
+    
   SGPropertyNode *wp_node = _gpsNode->getChild("wp", 0, true);
   SGPropertyNode* wp0_node = wp_node->getChild("wp", 0, true);
-  
   tieSGGeodReadOnly(wp0_node, _wp0_position, "longitude-deg", "latitude-deg", "altitude-ft");
+  tie(wp0_node, "ID", SGRawValueMethods<GPS, const char*>
+      (*this, &GPS::getWP0Ident, NULL));
+    
+    
   tie(_currentWayptNode, "ID", SGRawValueMethods<GPS, const char*>
     (*this, &GPS::getWP1Ident, NULL));
   
@@ -441,9 +285,12 @@ GPS::clearOutput()
 void
 GPS::update (double delta_time_sec)
 {
-  if (!_realismSimpleGps->getBoolValue()) {
+  if (!_defaultGPSMode) {
     // If it's off, don't bother.
-    if (!_serviceable_node->getBoolValue() || !_electrical_node->getBoolValue()) {
+      // check if value is defined, since many aircraft don't define an output
+      // for the GPS, but expect the default one to work.
+      bool elecOn = !_electrical_node->hasValue() || _electrical_node->getBoolValue();
+    if (!_serviceable_node->getBoolValue() || !elecOn) {
       clearOutput();
       return;
     }
@@ -454,7 +301,7 @@ GPS::update (double delta_time_sec)
   }    
   
   _raim_node->setDoubleValue(1.0);
-  _indicated_pos = _position.get();
+  _indicated_pos = globals->get_aircraft_position();
   updateBasicData(delta_time_sec);
 
   if (_dataValid) {
@@ -473,32 +320,27 @@ GPS::update (double delta_time_sec)
 
     
     updateTrackingBug();
-    updateReferenceNavaid(delta_time_sec);
     driveAutopilot();
   }
   
   if (_dataValid && (_mode == "init")) {
-        
-    if (_route_active_node->getBoolValue()) {
-      // GPS init with active route
-      SG_LOG(SG_INSTR, SG_INFO, "GPS init with active route");
-      selectLegMode();
-    } else {
+    // will select LEG mode if the route is active
+    routeManagerFlightPlanChanged(NULL);
+    
+    FGRouteMgr* routeMgr = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
+    if (!routeMgr->isRouteActive()) {
       // initialise in OBS mode, with waypt set to the nearest airport.
       // keep in mind at this point, _dataValid is not set
-    
-      auto_ptr<FGPositioned::Filter> f(createFilter(FGPositioned::AIRPORT));
-      FGPositionedRef apt = FGPositioned::findClosest(_position.get(), 20.0, f.get());
+      auto_ptr<FGPositioned::Filter> f(new FGAirport::HardSurfaceFilter());
+      FGPositionedRef apt = FGPositioned::findClosest(_indicated_pos, 20.0, f.get());
       if (apt) {
-        setScratchFromPositioned(apt, 0);
-        selectOBSMode();
+        selectOBSMode(new flightgear::NavaidWaypoint(apt, NULL));
       }
     }
 
     if (_mode != "init")
     {
       // allow a realistic delay in the future, here
-      SG_LOG(SG_INSTR, SG_INFO, "GPS initialisation complete");
     }
   } // of init mode check
   
@@ -506,6 +348,44 @@ GPS::update (double delta_time_sec)
   _lastPosValid = !(_last_pos == SGGeod());
 }
 
+void GPS::routeManagerFlightPlanChanged(SGPropertyNode*)
+{
+  if (_route) {
+    _route->removeDelegate(this);
+  }
+  
+  SG_LOG(SG_INSTR, SG_INFO, "GPS saw route-manager flight-plan replaced.");
+  FGRouteMgr* routeMgr = static_cast<FGRouteMgr*>(globals->get_subsystem("route-manager"));
+  _route = routeMgr->flightPlan();
+  if (_route) {
+    _route->addDelegate(this);
+  }
+  
+  if (routeMgr->isRouteActive()) {
+    selectLegMode();
+  } else {
+    selectOBSMode(_currentWaypt); // revert to OBS on current waypoint
+  }
+}
+
+void GPS::routeActivated(SGPropertyNode* aNode)
+{
+  bool isActive = aNode->getBoolValue();
+  if (isActive) {
+    SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, switching to LEG mode");
+    selectLegMode();
+    
+    // if we've already passed the current waypoint, sequence.
+    if (_dataValid && getWP1FromFlag()) {
+      SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, FROM wp1, sequencing");
+      sequence();
+    }
+  } else if (_mode == "leg") {
+    SG_LOG(SG_INSTR, SG_INFO, "GPS::route deactivated, switching to OBS mode");
+    selectOBSMode(_currentWaypt);
+  }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // implement the RNAV interface 
 SGGeod GPS::position()
@@ -592,7 +472,6 @@ GPS::updateBasicData(double dt)
   _trip_odometer_node->setDoubleValue(odometer + distance_m * SG_METER_TO_NM);
   
   if (!_dataValid) {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS setting data valid");
     _dataValid = true;
   }
 }
@@ -612,117 +491,28 @@ GPS::updateTrackingBug()
   _magnetic_bug_error_node->setDoubleValue(magnetic_bug_error);
 }
 
-void GPS::updateReferenceNavaid(double dt)
-{
-  if (!_ref_navaid_set) {
-    _ref_navaid_elapsed += dt;
-    if (_ref_navaid_elapsed > 5.0) {
-
-      FGPositioned::TypeFilter vorFilter(FGPositioned::VOR);
-      FGPositionedRef nav = FGPositioned::findClosest(_indicated_pos, 400.0, &vorFilter);
-      if (!nav) {
-        SG_LOG(SG_INSTR, SG_INFO, "GPS couldn't find a reference navaid");
-        _ref_navaid_id_node->setStringValue("");
-        _ref_navaid_name_node->setStringValue("");
-        _ref_navaid_bearing_node->setDoubleValue(0.0);
-        _ref_navaid_mag_bearing_node->setDoubleValue(0.0);
-        _ref_navaid_distance_node->setDoubleValue(0.0);
-        _ref_navaid_frequency_node->setStringValue("");
-      } else if (nav != _ref_navaid) {
-        SG_LOG(SG_INSTR, SG_INFO, "GPS code selected new ref-navaid:" << nav->ident());
-        _listener->setGuard(true);
-        _ref_navaid_id_node->setStringValue(nav->ident().c_str());
-        _ref_navaid_name_node->setStringValue(nav->name().c_str());
-        FGNavRecord* vor = (FGNavRecord*) nav.ptr();
-        _ref_navaid_frequency_node->setDoubleValue(vor->get_freq() / 100.0);
-        _listener->setGuard(false);
-      } else {
-        // SG_LOG(SG_INSTR, SG_ALERT, "matched existing");
-      }
-      
-      _ref_navaid = nav;
-      // reset elapsed time (do not do that before updating the properties above, since their
-      // listeners may request another update (_ref_navaid_elapsed = 9999), which results in
-      // excessive load (FGPositioned::findClosest called in every update loop...)
-      _ref_navaid_elapsed = 0.0; 
-    }
-  }
-  
-  if (_ref_navaid) {
-    double trueCourse, distanceM, az2;
-    SGGeodesy::inverse(_indicated_pos, _ref_navaid->geod(), trueCourse, az2, distanceM);
-    _ref_navaid_distance_node->setDoubleValue(distanceM * SG_METER_TO_NM);
-    _ref_navaid_bearing_node->setDoubleValue(trueCourse);
-    _ref_navaid_mag_bearing_node->setDoubleValue(trueCourse - _magvar_node->getDoubleValue());
-  }
-}
-
-void GPS::referenceNavaidSet(const std::string& aNavaid)
-{
-  _ref_navaid = NULL;
-  // allow setting an empty string to restore normal nearest-vor selection
-  if (aNavaid.size() > 0) {
-    FGPositioned::TypeFilter vorFilter(FGPositioned::VOR);
-    _ref_navaid = FGPositioned::findClosestWithIdent(aNavaid, 
-      _position.get(), &vorFilter);
-    
-    if (!_ref_navaid) {
-      SG_LOG(SG_INSTR, SG_ALERT, "GPS: unknown ref navaid:" << aNavaid);
-    }
-  }
-
-  if (_ref_navaid) {
-    _ref_navaid_set = true;
-    SG_LOG(SG_INSTR, SG_INFO, "GPS code set explicit ref-navaid:" << _ref_navaid->ident());
-    _ref_navaid_id_node->setStringValue(_ref_navaid->ident().c_str());
-    _ref_navaid_name_node->setStringValue(_ref_navaid->name().c_str());
-    FGNavRecord* vor = (FGNavRecord*) _ref_navaid.ptr();
-    _ref_navaid_frequency_node->setDoubleValue(vor->get_freq() / 100.0);
-  } else {
-    _ref_navaid_set = false;
-    _ref_navaid_elapsed = 9999.0; // update next tick
-  }
-}
-
-void GPS::routeActivated()
+void GPS::endOfFlightPlan()
 {
-  if (_route_active_node->getBoolValue()) {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, switching to LEG mode");
-    selectLegMode();
-    
-    // if we've already passed the current waypoint, sequence.
-    if (_dataValid && getWP1FromFlag()) {
-      SG_LOG(SG_INSTR, SG_INFO, "GPS::route activated, FROM wp1, sequencing");
-      _routeMgr->sequence();
-    }
-  } else if (_mode == "leg") {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS::route deactivated, switching to OBS mode");
-    // select OBS mode, but keep current waypoint-as is
-    _mode = "obs";
-    wp1Changed();
-  }
+  selectOBSMode(_currentWaypt);
 }
 
-void GPS::routeManagerSequenced()
+void GPS::currentWaypointChanged()
 {
-  if (_mode != "leg") {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS ignoring route sequencing, not in LEG mode");
+  if (!_route) {
     return;
   }
   
-  int index = _routeMgr->currentIndex(),
-    count = _routeMgr->numWaypts();
+  int index = _route->currentIndex(),
+    count = _route->numLegs();
   if ((index < 0) || (index >= count)) {
     _currentWaypt=NULL;
     _prevWaypt=NULL;
-    SG_LOG(SG_INSTR, SG_ALERT, "GPS: malformed route, index=" << index);
+    // no active leg on the route
     return;
   }
-  
-  SG_LOG(SG_INSTR, SG_INFO, "GPS waypoint index is now " << index);
-  
+    
   if (index > 0) {
-    _prevWaypt = _routeMgr->wayptAtIndex(index - 1);
+    _prevWaypt = _route->previousLeg()->waypoint();
     if (_prevWaypt->flag(WPT_DYNAMIC)) {
       _wp0_position = _indicated_pos;
     } else {
@@ -730,33 +520,48 @@ void GPS::routeManagerSequenced()
     }
   }
   
-  _currentWaypt = _routeMgr->currentWaypt();
-
+  _currentWaypt = _route->currentLeg()->waypoint();
   _desiredCourse = getLegMagCourse();
   _desiredCourseNode->fireValueChanged();
   wp1Changed();
 }
 
-void GPS::routeEdited()
+
+void GPS::waypointsChanged()
 {
   if (_mode != "leg") {
     return;
   }
   
   SG_LOG(SG_INSTR, SG_INFO, "GPS route edited while in LEG mode, updating waypoints");
-  routeManagerSequenced();
+  currentWaypointChanged();
 }
 
-void GPS::routeFinished()
+void GPS::cleared()
 {
-  if (_mode != "leg") {
-    return;
-  }
+    if (_mode != "leg") {
+        return;
+    }
+    
+    selectOBSMode(_currentWaypt);
+}
+
+void GPS::sequence()
+{
+    if (!_route) {
+        return;
+    }
   
-  SG_LOG(SG_INSTR, SG_INFO, "GPS route finished, reverting to OBS");
-  // select OBS mode, but keep current waypoint-as is
-  _mode = "obs";
-  wp1Changed();
+    int nextIndex = _route->currentIndex() + 1;
+    if (nextIndex >= _route->numLegs()) {
+        SG_LOG(SG_INSTR, SG_INFO, "sequenced final leg, end of route");
+        _route->finish();
+        selectOBSMode(_currentWaypt);
+        return;
+    }
+    
+    // will callback into currentWaypointChanged
+    _route->setCurrentIndex(nextIndex);
 }
 
 void GPS::updateTurn()
@@ -764,7 +569,7 @@ void GPS::updateTurn()
   bool printProgress = false;
   
   if (_computeTurnData) {
-    if (_last_speed_kts < 60) {
+    if (_last_speed_kts < 10) {
       // need valid leg course and sensible ground speed to compute the turn
       return;
     }
@@ -795,7 +600,7 @@ void GPS::updateTurn()
   if (_inTurn && !_turnSequenced && (progress > 0.5)) {
     _turnSequenced = true;
      SG_LOG(SG_INSTR, SG_INFO, "turn passed midpoint, sequencing");
-     _routeMgr->sequence();
+     sequence();
   }
   
   if (_inTurn && (progress >= 1.0)) {
@@ -826,12 +631,13 @@ void GPS::updateOverflight()
     SG_LOG(SG_INSTR, SG_INFO, "GPS DTO reached destination point");
     
     // check for wp1 being on active route - resume leg mode
-    if (_routeMgr->isRouteActive()) {
-      int index = _routeMgr->flightPlan()->findWayptIndex(_currentWaypt->position());
+    if (_route) {
+      int index = _route->findWayptIndex(_currentWaypt->position());
       if (index >= 0) {
         SG_LOG(SG_INSTR, SG_INFO, "GPS DTO, resuming LEG mode at wp:" << index);
         _mode = "leg";
-        _routeMgr->jumpToIndex(index);
+        _route->setCurrentIndex(index);
+        sequence(); // and sequence to the next point
       }
     }
     
@@ -842,8 +648,8 @@ void GPS::updateOverflight()
       wp1Changed();
     }
   } else if (_mode == "leg") {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS doing overflight sequencing");
-    _routeMgr->sequence();
+    SG_LOG(SG_INSTR, SG_DEBUG, "GPS doing overflight sequencing");
+    sequence();
   } else if (_mode == "obs") {
     // nothing to do here, TO/FROM will update but that's fine
   }
@@ -874,18 +680,13 @@ double GPS::computeTurnProgress(double aBearing) const
 void GPS::computeTurnData()
 {
   _computeTurnData = false;
-  if (_mode != "leg") { // and approach modes in the future
+  if ((_mode != "leg") || !_route->nextLeg()) {
     _anticipateTurn = false;
     return;
   }
   
-  WayptRef next = _routeMgr->wayptAtIndex(_routeMgr->currentIndex() + 1);
-  if (!next || next->flag(WPT_DYNAMIC)) {
-    _anticipateTurn = false;
-    return;
-  }
-  
-  if (!_config.turnAnticipationEnabled()) {
+  WayptRef next = _route->nextLeg()->waypoint();
+  if (next->flag(WPT_DYNAMIC) || !_config.turnAnticipationEnabled()) {
     _anticipateTurn = false;
     return;
   }
@@ -957,9 +758,9 @@ void GPS::updateRouteData()
 {
   double totalDistance = _wayptController->distanceToWayptM() * SG_METER_TO_NM;
   // walk all waypoints from wp2 to route end, and sum
-  for (int i=_routeMgr->currentIndex()+1; i<_routeMgr->numWaypts(); ++i) {
// for (int i=_routeMgr->currentIndex()+1; i<_routeMgr->numWaypts(); ++i) {
     //totalDistance += _routeMgr->get_waypoint(i).get_distance();
-  }
+  //}
   
   _routeDistanceNm->setDoubleValue(totalDistance * SG_METER_TO_NM);
   if (_last_speed_kts > 1.0) {
@@ -970,7 +771,7 @@ void GPS::updateRouteData()
 
 void GPS::driveAutopilot()
 {
-  if (!_config.driveAutopilot() || !_realismSimpleGps->getBoolValue()) {
+  if (!_config.driveAutopilot() || !_defaultGPSMode) {
     _apDrivingFlag->setBoolValue(false);
     return;
   }
@@ -1007,21 +808,6 @@ void GPS::wp1Changed()
     _wayptController->update();
     _legDistanceNm = _wayptController->distanceToWayptM() * SG_METER_TO_NM;
   }
-  
-  if (!_config.driveAutopilot()) {
-    return;
-  }
-  
-  RouteRestriction ar = _currentWaypt->altitudeRestriction();
-  double restrictAlt = _currentWaypt->altitudeFt();
-  double alt = _indicated_pos.getElevationFt();
-  if ((ar == RESTRICT_AT) ||
-       ((ar == RESTRICT_ABOVE) && (alt < restrictAlt)) ||
-       ((ar == RESTRICT_BELOW) && (alt > restrictAlt)))
-  {
-    SG_LOG(SG_AUTOPILOT, SG_INFO, "current waypt has altitude set, setting on AP");
-    _apTargetAltitudeFt->setDoubleValue(restrictAlt);
-  }
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -1212,96 +998,101 @@ bool GPS::getWP1FromFlag() const
   return !getWP1ToFlag();
 }
 
+#if FG_210_COMPAT
 double GPS::getScratchDistance() const
 {
-  if (!_scratchValid) {
-    return 0.0;
-  }
-  
-  return SGGeodesy::distanceNm(_indicated_pos, _scratchPos);
+    if (!_scratchValid) {
+        return 0.0;
+    }
+    
+    return SGGeodesy::distanceNm(_indicated_pos, _scratchPos);
 }
 
 double GPS::getScratchTrueBearing() const
 {
-  if (!_scratchValid) {
-    return 0.0;
-  }
-
-  return SGGeodesy::courseDeg(_indicated_pos, _scratchPos);
+    if (!_scratchValid) {
+        return 0.0;
+    }
+    
+    return SGGeodesy::courseDeg(_indicated_pos, _scratchPos);
 }
 
 double GPS::getScratchMagBearing() const
 {
-  if (!_scratchValid) {
-    return 0.0;
-  }
-  
-  double crs = getScratchTrueBearing() - _magvar_node->getDoubleValue();
-  SG_NORMALIZE_RANGE(crs, 0.0, 360.0);
-  return crs;
+    if (!_scratchValid) {
+        return 0.0;
+    }
+    
+    double crs = getScratchTrueBearing() - _magvar_node->getDoubleValue();
+    SG_NORMALIZE_RANGE(crs, 0.0, 360.0);
+    return crs;
 }
 
+#endif
+
 /////////////////////////////////////////////////////////////////////////////
-// command / scratch / search system
+// scratch system
 
 void GPS::setCommand(const char* aCmd)
 {
-  SG_LOG(SG_INSTR, SG_INFO, "GPS command:" << aCmd);
+  SG_LOG(SG_INSTR, SG_DEBUG, "GPS command:" << aCmd);
   
   if (!strcmp(aCmd, "direct")) {
     directTo();
   } else if (!strcmp(aCmd, "obs")) {
-    selectOBSMode();
+    selectOBSMode(NULL);
   } else if (!strcmp(aCmd, "leg")) {
     selectLegMode();
+#if FG_210_COMPAT
   } else if (!strcmp(aCmd, "load-route-wpt")) {
-    loadRouteWaypoint();
+      loadRouteWaypoint();
   } else if (!strcmp(aCmd, "nearest")) {
-    loadNearest();
+      loadNearest();
   } else if (!strcmp(aCmd, "search")) {
-    _searchNames = false;
-    search();
+      _searchNames = false;
+      search();
   } else if (!strcmp(aCmd, "search-names")) {
-    _searchNames = true;
-    search();
+      _searchNames = true;
+      search();
   } else if (!strcmp(aCmd, "next")) {
-    nextResult();
+      nextResult();
   } else if (!strcmp(aCmd, "previous")) {
-    previousResult();
+      previousResult();
   } else if (!strcmp(aCmd, "define-user-wpt")) {
-    defineWaypoint();
+      defineWaypoint();
   } else if (!strcmp(aCmd, "route-insert-before")) {
-    int index = _scratchNode->getIntValue("index");
-    if (index < 0 || (_routeMgr->numWaypts() == 0)) {
-      index = _routeMgr->numWaypts();
-    } else if (index >= _routeMgr->numWaypts()) {
-      SG_LOG(SG_INSTR, SG_WARN, "GPS:route-insert-before, bad index:" << index);
-      return;
-    }
-    
-    insertWaypointAtIndex(index);
+      int index = _scratchNode->getIntValue("index");
+      if (index < 0 || (_route->numLegs() == 0)) {
+          index = _route->numLegs();
+      } else if (index >= _route->numLegs()) {
+          SG_LOG(SG_INSTR, SG_WARN, "GPS:route-insert-before, bad index:" << index);
+          return;
+      }
+      
+      insertWaypointAtIndex(index);
   } else if (!strcmp(aCmd, "route-insert-after")) {
-    int index = _scratchNode->getIntValue("index");
-    if (index < 0 || (_routeMgr->numWaypts() == 0)) {
-      index = _routeMgr->numWaypts();
-    } else if (index >= _routeMgr->numWaypts()) {
-      SG_LOG(SG_INSTR, SG_WARN, "GPS:route-insert-after, bad index:" << index);
-      return;
-    } else {
-      ++index; 
-    }
-  
-    insertWaypointAtIndex(index);
+      int index = _scratchNode->getIntValue("index");
+      if (index < 0 || (_route->numLegs() == 0)) {
+          index = _route->numLegs();
+      } else if (index >= _route->numLegs()) {
+          SG_LOG(SG_INSTR, SG_WARN, "GPS:route-insert-after, bad index:" << index);
+          return;
+      } else {
+          ++index;
+      }
+      
+      insertWaypointAtIndex(index);
   } else if (!strcmp(aCmd, "route-delete")) {
-    int index = _scratchNode->getIntValue("index");
-    if (index < 0) {
-      index = _routeMgr->numWaypts();
-    } else if (index >= _routeMgr->numWaypts()) {
-      SG_LOG(SG_INSTR, SG_WARN, "GPS:route-delete, bad index:" << index);
-      return;
-    }
-    
-    removeWaypointAtIndex(index);
+      int index = _scratchNode->getIntValue("index");
+      if (index < 0) {
+          index = _route->numLegs();
+      } else if (index >= _route->numLegs()) {
+          SG_LOG(SG_INSTR, SG_WARN, "GPS:route-delete, bad index:" << index);
+          return;
+      }
+      
+      removeWaypointAtIndex(index);
+#endif
   } else {
     SG_LOG(SG_INSTR, SG_WARN, "GPS:unrecognized command:" << aCmd);
   }
@@ -1310,9 +1101,11 @@ void GPS::setCommand(const char* aCmd)
 void GPS::clearScratch()
 {
   _scratchPos = SGGeod::fromDegFt(-9999.0, -9999.0, -9999.0);
-  _scratchValid = false;  
-  _scratchNode->setStringValue("type", "");
-  _scratchNode->setStringValue("query", "");
+  _scratchNode->setBoolValue("valid", false);
+#if FG_210_COMPAT
+    _scratchNode->setStringValue("type", "");
+    _scratchNode->setStringValue("query", "");
+#endif
 }
 
 bool GPS::isScratchPositionValid() const
@@ -1340,360 +1133,359 @@ void GPS::directTo()
   wp1Changed();
 }
 
-void GPS::loadRouteWaypoint()
+void GPS::selectOBSMode(flightgear::Waypt* waypt)
 {
-  _scratchValid = false;
-//  if (!_routeMgr->isRouteActive()) {
-//    SG_LOG(SG_INSTR, SG_WARN, "GPS:loadWaypoint: no active route");
-//    return;
-//  }
-  
-  int index = _scratchNode->getIntValue("index", -9999);
-  clearScratch();
-  
-  if ((index < 0) || (index >= _routeMgr->numWaypts())) { // no index supplied, use current wp
-    index = _routeMgr->currentIndex();
+  if (!waypt) {
+    // initialise from scratch
+    if (!isScratchPositionValid()) {
+      return;
+    }
+    
+    waypt = new BasicWaypt(_scratchPos, _scratchNode->getStringValue("ident"), NULL);
   }
   
-  _searchIsRoute = true;
-  setScratchFromRouteWaypoint(index);
+  _mode = "obs";
+  _currentWaypt = waypt;
+  _wp0_position = _indicated_pos;
+  wp1Changed();
 }
 
-void GPS::setScratchFromRouteWaypoint(int aIndex)
+void GPS::selectLegMode()
 {
-  assert(_searchIsRoute);
-  if ((aIndex < 0) || (aIndex >= _routeMgr->numWaypts())) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:setScratchFromRouteWaypoint: route-index out of bounds");
+  if (_mode == "leg") {
     return;
   }
   
-  _searchResultIndex = aIndex;
-  WayptRef wp = _routeMgr->wayptAtIndex(aIndex);
-  _scratchNode->setStringValue("ident", wp->ident());
-  _scratchPos = wp->position();
-  _scratchValid = true;
-  _scratchNode->setIntValue("index", aIndex);
+  if (!_route) {
+    SG_LOG(SG_INSTR, SG_WARN, "GPS:selectLegMode: no active route");
+    return;
+  }
+
+  _mode = "leg";  
+  // depending on the situation, this will either get over-written 
+  // in routeManagerSequenced or not; either way it does no harm to
+  // set it here.
+  _wp0_position = _indicated_pos;
+
+  // not really sequenced, but does all the work of updating wp0/1
+  currentWaypointChanged();
+}
+
+#if FG_210_COMPAT
+
+void GPS::loadRouteWaypoint()
+{
+    _scratchValid = false;    
+    int index = _scratchNode->getIntValue("index", -9999);
+    clearScratch();
+    
+    if ((index < 0) || (index >= _route->numLegs())) { // no index supplied, use current wp
+        index = _route->currentIndex();
+    }
+    
+    _searchIsRoute = true;
+    setScratchFromRouteWaypoint(index);
+}
+
+void GPS::setScratchFromRouteWaypoint(int aIndex)
+{
+    assert(_searchIsRoute);
+    if ((aIndex < 0) || (aIndex >= _route->numLegs())) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:setScratchFromRouteWaypoint: route-index out of bounds");
+        return;
+    }
+    
+    _searchResultIndex = aIndex;
+    WayptRef wp = _route->legAtIndex(aIndex)->waypoint();
+    _scratchNode->setStringValue("ident", wp->ident());
+    _scratchPos = wp->position();
+    _scratchValid = true;
+    _scratchNode->setIntValue("index", aIndex);
 }
 
 void GPS::loadNearest()
 {
-  string sty(_scratchNode->getStringValue("type"));
-  FGPositioned::Type ty = FGPositioned::typeFromName(sty);
-  if (ty == FGPositioned::INVALID) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:loadNearest: request type is invalid:" << sty);
-    return;
-  }
-  
-  auto_ptr<FGPositioned::Filter> f(createFilter(ty));
-  int limitCount = _scratchNode->getIntValue("max-results", 1);
-  double cutoffDistance = _scratchNode->getDoubleValue("cutoff-nm", 400.0);
-  
-  SGGeod searchPos = _indicated_pos;
-  if (isScratchPositionValid()) {
-    searchPos = _scratchPos;
-  }
-  
-  clearScratch(); // clear now, regardless of whether we find a match or not
+    string sty(_scratchNode->getStringValue("type"));
+    FGPositioned::Type ty = FGPositioned::typeFromName(sty);
+    if (ty == FGPositioned::INVALID) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:loadNearest: request type is invalid:" << sty);
+        return;
+    }
+    
+    auto_ptr<FGPositioned::Filter> f(createFilter(ty));
+    int limitCount = _scratchNode->getIntValue("max-results", 1);
+    double cutoffDistance = _scratchNode->getDoubleValue("cutoff-nm", 400.0);
+    
+    SGGeod searchPos = _indicated_pos;
+    if (isScratchPositionValid()) {
+        searchPos = _scratchPos;
+    }
+    
+    clearScratch(); // clear now, regardless of whether we find a match or not
     
-  _searchResults = 
+    _searchResults =
     FGPositioned::findClosestN(searchPos, limitCount, cutoffDistance, f.get());
-  _searchResultIndex = 0;
-  _searchIsRoute = false;
-  
-  if (_searchResults.empty()) {
-    SG_LOG(SG_INSTR, SG_INFO, "GPS:loadNearest: no matches at all");
-    return;
-  }
-  
-  setScratchFromCachedSearchResult();
+    _searchResultIndex = 0;
+    _searchIsRoute = false;
+    
+    if (_searchResults.empty()) {
+        return;
+    }
+    
+    setScratchFromCachedSearchResult();
 }
 
 bool GPS::SearchFilter::pass(FGPositioned* aPos) const
 {
-  switch (aPos->type()) {
-  case FGPositioned::AIRPORT:
-  // heliport and seaport too?
-  case FGPositioned::VOR:
-  case FGPositioned::NDB:
-  case FGPositioned::FIX:
-  case FGPositioned::TACAN:
-  case FGPositioned::WAYPOINT:
-    return true;
-  default:
-    return false;
-  }
+    switch (aPos->type()) {
+        case FGPositioned::AIRPORT:
+            // heliport and seaport too?
+        case FGPositioned::VOR:
+        case FGPositioned::NDB:
+        case FGPositioned::FIX:
+        case FGPositioned::TACAN:
+        case FGPositioned::WAYPOINT:
+            return true;
+        default:
+            return false;
+    }
 }
 
 FGPositioned::Type GPS::SearchFilter::minType() const
 {
-  return FGPositioned::AIRPORT;
+    return FGPositioned::AIRPORT;
 }
 
 FGPositioned::Type GPS::SearchFilter::maxType() const
 {
-  return FGPositioned::WAYPOINT;
+    return FGPositioned::VOR;
 }
 
 FGPositioned::Filter* GPS::createFilter(FGPositioned::Type aTy)
 {
-  if (aTy == FGPositioned::AIRPORT) {
-    return new FGAirport::HardSurfaceFilter();
-  }
-  
-  // if we were passed INVALID, assume it means 'all types interesting to a GPS'
-  if (aTy == FGPositioned::INVALID) {
-    return new SearchFilter;
-  }
-  
-  return new FGPositioned::TypeFilter(aTy);
+    if (aTy == FGPositioned::AIRPORT) {
+        return new FGAirport::HardSurfaceFilter();
+    }
+    
+    // if we were passed INVALID, assume it means 'all types interesting to a GPS'
+    if (aTy == FGPositioned::INVALID) {
+        return new SearchFilter;
+    }
+    
+    return new FGPositioned::TypeFilter(aTy);
 }
 
 void GPS::search()
 {
-  // parse search terms into local members, and exec the first search
-  string sty(_scratchNode->getStringValue("type"));
-  _searchType = FGPositioned::typeFromName(sty);
-  _searchQuery = _scratchNode->getStringValue("query");
-  if (_searchQuery.empty()) {
-    SG_LOG(SG_INSTR, SG_WARN, "empty GPS search query");
-    clearScratch();
-    return;
-  }
-  
-  _searchExact = _scratchNode->getBoolValue("exact", true);
-  _searchResultIndex = 0;
-  _searchIsRoute = false;
-
-  auto_ptr<FGPositioned::Filter> f(createFilter(_searchType));
-  if (_searchNames) {
-    _searchResults = FGPositioned::findAllWithName(_searchQuery, f.get(), _searchExact);
-  } else {
-    _searchResults = FGPositioned::findAllWithIdent(_searchQuery, f.get(), _searchExact);
-  }
-  
-  bool orderByRange = _scratchNode->getBoolValue("order-by-distance", true);
-  if (orderByRange) {
-    FGPositioned::sortByRange(_searchResults, _indicated_pos);
-  }
-  
-  if (_searchResults.empty()) {
-    clearScratch();
-    return;
-  }
-  
-  setScratchFromCachedSearchResult();
+    // parse search terms into local members, and exec the first search
+    string sty(_scratchNode->getStringValue("type"));
+    _searchType = FGPositioned::typeFromName(sty);
+    _searchQuery = _scratchNode->getStringValue("query");
+    if (_searchQuery.empty()) {
+        SG_LOG(SG_INSTR, SG_WARN, "empty GPS search query");
+        clearScratch();
+        return;
+    }
+    
+    _searchExact = _scratchNode->getBoolValue("exact", true);
+    _searchResultIndex = 0;
+    _searchIsRoute = false;
+    
+    auto_ptr<FGPositioned::Filter> f(createFilter(_searchType));
+    if (_searchNames) {
+        _searchResults = FGPositioned::findAllWithName(_searchQuery, f.get(), _searchExact);
+    } else {
+        _searchResults = FGPositioned::findAllWithIdent(_searchQuery, f.get(), _searchExact);
+    }
+    
+    bool orderByRange = _scratchNode->getBoolValue("order-by-distance", true);
+    if (orderByRange) {
+        FGPositioned::sortByRange(_searchResults, _indicated_pos);
+    }
+    
+    if (_searchResults.empty()) {
+        clearScratch();
+        return;
+    }
+    
+    setScratchFromCachedSearchResult();
 }
 
 bool GPS::getScratchHasNext() const
 {
-  int lastResult;
-  if (_searchIsRoute) {
-    lastResult = _routeMgr->numWaypts() - 1;
-  } else {
-    lastResult = (int) _searchResults.size() - 1;
-  }
-
-  if (lastResult < 0) { // search array might be empty
-    return false;
-  }
-  
-  return (_searchResultIndex < lastResult);
+    int lastResult;
+    if (_searchIsRoute) {
+        lastResult = _route->numLegs() - 1;
+    } else {
+        lastResult = (int) _searchResults.size() - 1;
+    }
+    
+    if (lastResult < 0) { // search array might be empty
+        return false;
+    }
+    
+    return (_searchResultIndex < lastResult);
 }
 
 void GPS::setScratchFromCachedSearchResult()
 {
-  int index = _searchResultIndex;
-  
-  if ((index < 0) || (index >= (int) _searchResults.size())) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:setScratchFromCachedSearchResult: index out of bounds:" << index);
-    return;
-  }
-  
-  setScratchFromPositioned(_searchResults[index], index);
+    int index = _searchResultIndex;
+    
+    if ((index < 0) || (index >= (int) _searchResults.size())) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:setScratchFromCachedSearchResult: index out of bounds:" << index);
+        return;
+    }
+    
+    setScratchFromPositioned(_searchResults[index], index);
 }
 
 void GPS::setScratchFromPositioned(FGPositioned* aPos, int aIndex)
 {
-  clearScratch();
-  assert(aPos);
-
-  _scratchPos = aPos->geod();
-  _scratchNode->setStringValue("name", aPos->name());
-  _scratchNode->setStringValue("ident", aPos->ident());
-  _scratchNode->setStringValue("type", FGPositioned::nameForType(aPos->type()));
+    clearScratch();
+    assert(aPos);
     
-  if (aIndex >= 0) {
-    _scratchNode->setIntValue("index", aIndex);
-  }
-  
-  _scratchValid = true;
-  _scratchNode->setIntValue("result-count", _searchResults.size());
-  
-  switch (aPos->type()) {
-  case FGPositioned::VOR:
-    _scratchNode->setDoubleValue("frequency-mhz", static_cast<FGNavRecord*>(aPos)->get_freq() / 100.0);
-    break;
-  
-  case FGPositioned::NDB:
-    _scratchNode->setDoubleValue("frequency-khz", static_cast<FGNavRecord*>(aPos)->get_freq() / 100.0);
-    break;
-  
-  case FGPositioned::AIRPORT:
-    addAirportToScratch((FGAirport*)aPos);
-    break;
-  
-  default:
-      // no-op
-      break;
-  }
-  
-  // look for being on the route and set?
-}
-
-void GPS::addAirportToScratch(FGAirport* aAirport)
-{
-  for (unsigned int r=0; r<aAirport->numRunways(); ++r) {
-    SGPropertyNode* rwyNd = _scratchNode->getChild("runways", r, true);
-    FGRunway* rwy = aAirport->getRunwayByIndex(r);
-    // TODO - filter out unsuitable runways in the future
-    // based on config again
+    _scratchPos = aPos->geod();
+    _scratchNode->setStringValue("name", aPos->name());
+    _scratchNode->setStringValue("ident", aPos->ident());
+    _scratchNode->setStringValue("type", FGPositioned::nameForType(aPos->type()));
+    
+    if (aIndex >= 0) {
+        _scratchNode->setIntValue("index", aIndex);
+    }
     
-    rwyNd->setStringValue("id", rwy->ident().c_str());
-    rwyNd->setIntValue("length-ft", rwy->lengthFt());
-    rwyNd->setIntValue("width-ft", rwy->widthFt());
-    rwyNd->setIntValue("heading-deg", rwy->headingDeg());
-    // map surface code to a string
-    // TODO - lighting information
+    _scratchValid = true;
+    _scratchNode->setIntValue("result-count", _searchResults.size());
     
-    if (rwy->ILS()) {
-      rwyNd->setDoubleValue("ils-frequency-mhz", rwy->ILS()->get_freq() / 100.0);
+    switch (aPos->type()) {
+        case FGPositioned::VOR:
+            _scratchNode->setDoubleValue("frequency-mhz", static_cast<FGNavRecord*>(aPos)->get_freq() / 100.0);
+            break;
+            
+        case FGPositioned::NDB:
+            _scratchNode->setDoubleValue("frequency-khz", static_cast<FGNavRecord*>(aPos)->get_freq() / 100.0);
+            break;
+            
+        case FGPositioned::AIRPORT:
+            addAirportToScratch((FGAirport*)aPos);
+            break;
+            
+        default:
+            // no-op
+            break;
     }
-  } // of runways iteration
-}
-
-
-void GPS::selectOBSMode()
-{
-  if (!isScratchPositionValid()) {
-    return;
-  }
-  
-  SG_LOG(SG_INSTR, SG_INFO, "GPS switching to OBS mode");
-  _mode = "obs";
-
-  _currentWaypt = new BasicWaypt(_scratchPos, _scratchNode->getStringValue("ident"), NULL);
-  _wp0_position = _indicated_pos;
-  wp1Changed();
+    
+    // look for being on the route and set?
 }
 
-void GPS::selectLegMode()
+void GPS::addAirportToScratch(FGAirport* aAirport)
 {
-  if (_mode == "leg") {
-    return;
-  }
-  
-  if (!_routeMgr->isRouteActive()) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:selectLegMode: no active route");
-    return;
-  }
-
-  SG_LOG(SG_INSTR, SG_INFO, "GPS switching to LEG mode");
-  _mode = "leg";
-  
-  // depending on the situation, this will either get over-written 
-  // in routeManagerSequenced or not; either way it does no harm to
-  // set it here.
-  _wp0_position = _indicated_pos;
-
-  // not really sequenced, but does all the work of updating wp0/1
-  routeManagerSequenced();
+    for (unsigned int r=0; r<aAirport->numRunways(); ++r) {
+        SGPropertyNode* rwyNd = _scratchNode->getChild("runways", r, true);
+        FGRunway* rwy = aAirport->getRunwayByIndex(r);
+        // TODO - filter out unsuitable runways in the future
+        // based on config again
+        
+        rwyNd->setStringValue("id", rwy->ident().c_str());
+        rwyNd->setIntValue("length-ft", rwy->lengthFt());
+        rwyNd->setIntValue("width-ft", rwy->widthFt());
+        rwyNd->setIntValue("heading-deg", rwy->headingDeg());
+        // map surface code to a string
+        // TODO - lighting information
+        
+        if (rwy->ILS()) {
+            rwyNd->setDoubleValue("ils-frequency-mhz", rwy->ILS()->get_freq() / 100.0);
+        }
+    } // of runways iteration
 }
 
 void GPS::nextResult()
 {
-  if (!getScratchHasNext()) {
-    return;
-  }
-  
-  clearScratch();
-  if (_searchIsRoute) {
-    setScratchFromRouteWaypoint(++_searchResultIndex);
-  } else {
-    ++_searchResultIndex;
-    setScratchFromCachedSearchResult();
-  }
+    if (!getScratchHasNext()) {
+        return;
+    }
+    
+    clearScratch();
+    if (_searchIsRoute) {
+        setScratchFromRouteWaypoint(++_searchResultIndex);
+    } else {
+        ++_searchResultIndex;
+        setScratchFromCachedSearchResult();
+    }
 }
 
 void GPS::previousResult()
 {
-  if (_searchResultIndex <= 0) {
-    return;
-  }
-  
-  clearScratch();
-  --_searchResultIndex;
-  
-  if (_searchIsRoute) {
-    setScratchFromRouteWaypoint(_searchResultIndex);
-  } else {
-    setScratchFromCachedSearchResult();
-  }
+    if (_searchResultIndex <= 0) {
+        return;
+    }
+    
+    clearScratch();
+    --_searchResultIndex;
+    
+    if (_searchIsRoute) {
+        setScratchFromRouteWaypoint(_searchResultIndex);
+    } else {
+        setScratchFromCachedSearchResult();
+    }
 }
 
 void GPS::defineWaypoint()
 {
-  if (!isScratchPositionValid()) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: invalid lat/lon");
-    return;
-  }
-  
-  string ident = _scratchNode->getStringValue("ident");
-  if (ident.size() < 2) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: waypoint identifier must be at least two characters");
-    return;
-  }
+    if (!isScratchPositionValid()) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: invalid lat/lon");
+        return;
+    }
     
-// check for duplicate idents
-  FGPositioned::TypeFilter f(FGPositioned::WAYPOINT);
-  FGPositioned::List dups = FGPositioned::findAllWithIdent(ident, &f);
-  if (!dups.empty()) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: non-unique waypoint identifier, ho-hum");
-  }
-  
-  SG_LOG(SG_INSTR, SG_INFO, "GPS:defineWaypoint: creating waypoint:" << ident);
-  FGPositionedRef wpt = FGPositioned::createUserWaypoint(ident, _scratchPos);
-  _searchResults.clear();
-  _searchResults.push_back(wpt);
-  setScratchFromPositioned(wpt.get(), -1);
+    string ident = _scratchNode->getStringValue("ident");
+    if (ident.size() < 2) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: waypoint identifier must be at least two characters");
+        return;
+    }
+    
+    // check for duplicate idents
+    FGPositioned::TypeFilter f(FGPositioned::WAYPOINT);
+    FGPositionedList dups = FGPositioned::findAllWithIdent(ident, &f);
+    if (!dups.empty()) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:defineWaypoint: non-unique waypoint identifier, ho-hum");
+    }
+    
+    SG_LOG(SG_INSTR, SG_INFO, "GPS:defineWaypoint: creating waypoint:" << ident);
+    FGPositionedRef wpt = FGPositioned::createUserWaypoint(ident, _scratchPos);
+    _searchResults.clear();
+    _searchResults.push_back(wpt);
+    setScratchFromPositioned(wpt.get(), -1);
 }
 
 void GPS::insertWaypointAtIndex(int aIndex)
 {
-  // note we do allow index = routeMgr->size(), that's an append
-  if ((aIndex < 0) || (aIndex > _routeMgr->numWaypts())) {
-    throw sg_range_exception("GPS::insertWaypointAtIndex: index out of bounds");
-  }
-  
-  if (!isScratchPositionValid()) {
-    SG_LOG(SG_INSTR, SG_WARN, "GPS:insertWaypointAtIndex: invalid lat/lon");
-    return;
-  }
-  
-  string ident = _scratchNode->getStringValue("ident");
-
-  WayptRef wpt = new BasicWaypt(_scratchPos, ident, NULL);
-  _routeMgr->flightPlan()->insertWayptAtIndex(wpt, aIndex);
+    // note we do allow index = routeMgr->size(), that's an append
+    if ((aIndex < 0) || (aIndex > _route->numLegs())) {
+        throw sg_range_exception("GPS::insertWaypointAtIndex: index out of bounds");
+    }
+    
+    if (!isScratchPositionValid()) {
+        SG_LOG(SG_INSTR, SG_WARN, "GPS:insertWaypointAtIndex: invalid lat/lon");
+        return;
+    }
+    
+    string ident = _scratchNode->getStringValue("ident");
+    
+    WayptRef wpt = new BasicWaypt(_scratchPos, ident, NULL);
+    _route->insertWayptAtIndex(wpt, aIndex);
 }
 
 void GPS::removeWaypointAtIndex(int aIndex)
 {
-  if ((aIndex < 0) || (aIndex >= _routeMgr->numWaypts())) {
-    throw sg_range_exception("GPS::removeWaypointAtIndex: index out of bounds");
-  }
-  
-  _routeMgr->removeLegAtIndex(aIndex);
+    if ((aIndex < 0) || (aIndex >= _route->numLegs())) {
+        throw sg_range_exception("GPS::removeWaypointAtIndex: index out of bounds");
+    }
+    
+    _route->deleteIndex(aIndex);
 }
 
+
+#endif // of FG_210_COMPAT
+
 void GPS::tieSGGeod(SGPropertyNode* aNode, SGGeod& aRef, 
   const char* lonStr, const char* latStr, const char* altStr)
 {