+ friend class GPSListener;
+ friend class SearchFilter;
+
+ /**
+ * Configuration manager, track data relating to aircraft installation
+ */
+ class Config
+ {
+ public:
+ Config();
+
+ void bind(GPS* aOwner, SGPropertyNode* aCfg);
+
+ bool turnAnticipationEnabled() const
+ { return _enableTurnAnticipation; }
+
+ /**
+ * Desired turn rate in degrees/second. From this we derive the turn
+ * radius and hence how early we need to anticipate it.
+ */
+ double turnRateDegSec() const
+ { return _turnRate; }
+
+ /**
+ * Distance at which we arm overflight sequencing. Once inside this
+ * distance, a change of the wp1 'TO' flag to false will be considered
+ * overlight of the wp.
+ */
+ double overflightArmDistanceNm() const
+ { return _overflightArmDistance; }
+
+ /**
+ * Time before the next WP to activate an external annunciator
+ */
+ double waypointAlertTime() const
+ { return _waypointAlertTime; }
+
+ bool requireHardSurface() const
+ { return _requireHardSurface; }
+
+ double minRunwayLengthFt() const
+ { return _minRunwayLengthFt; }
+
+ bool cdiDeflectionIsAngular() const
+ { return (_cdiMaxDeflectionNm <= 0.0); }
+
+ double cdiDeflectionLinearPeg() const
+ {
+ assert(_cdiMaxDeflectionNm > 0.0);
+ return _cdiMaxDeflectionNm;
+ }
+
+ bool driveAutopilot() const
+ { return _driveAutopilot; }
+
+ bool courseSelectable() const
+ { return _courseSelectable; }
+ private:
+ bool _enableTurnAnticipation;
+
+ // desired turn rate in degrees per second
+ double _turnRate;
+
+ // distance from waypoint to arm overflight sequencing (in nm)
+ double _overflightArmDistance;
+
+ // time before reaching a waypoint to trigger annunicator light/sound
+ // (in seconds)
+ double _waypointAlertTime;
+
+ // minimum runway length to require when filtering
+ double _minRunwayLengthFt;
+
+ // should we require a hard-surfaced runway when filtering?
+ bool _requireHardSurface;
+
+ double _cdiMaxDeflectionNm;
+
+ // should we drive the autopilot directly or not?
+ bool _driveAutopilot;
+
+ // is selected-course-deg read to set desired-course or not?
+ bool _courseSelectable;
+ };
+
+ class SearchFilter : public FGPositioned::Filter
+ {
+ public:
+ virtual bool pass(FGPositioned* aPos) const;
+
+ virtual FGPositioned::Type minType() const;
+ virtual FGPositioned::Type maxType() const;
+ };
+
+ /**
+ * reset all output properties to default / non-service values
+ */
+ void clearOutput();
+
+ void updateBasicData(double dt);
+
+ void updateTrackingBug();
+ void updateReferenceNavaid(double dt);
+ void referenceNavaidSet(const std::string& aNavaid);
+ void updateRouteData();
+ void driveAutopilot();
+
+ void routeActivated();
+ void routeManagerSequenced();
+ void routeEdited();
+ void routeFinished();
+
+ void updateTurn();
+ void updateOverflight();
+ void beginTurn();
+ void endTurn();
+
+ double computeTurnProgress(double aBearing) const;
+ void computeTurnData();
+ void updateTurnData();
+ double computeTurnRadiusNm(double aGroundSpeedKts) const;
+
+ /**
+ * Update one-shot things when WP1 / leg data change
+ */
+ void wp1Changed();
+
+// scratch maintenence utilities
+ void setScratchFromPositioned(FGPositioned* aPos, int aIndex);
+ void setScratchFromCachedSearchResult();
+ void setScratchFromRouteWaypoint(int aIndex);
+
+ /**
+ * Add airport-specific information to a scratch result
+ */
+ void addAirportToScratch(FGAirport* aAirport);
+
+ void clearScratch();
+
+ /**
+ * Predicate, determine if the lon/lat position in the scratch is
+ * valid or not.
+ */
+ bool isScratchPositionValid() const;
+
+ FGPositioned::Filter* createFilter(FGPositioned::Type aTy);
+
+ /**
+ * Search kernel - called each time we step through a result
+ */
+ void performSearch();
+
+// command handlers
+ void selectLegMode();
+ void selectOBSMode();
+ void directTo();
+ void loadRouteWaypoint();
+ void loadNearest();
+ void search();
+ void nextResult();
+ void previousResult();
+ void defineWaypoint();
+ void insertWaypointAtIndex(int aIndex);
+ void removeWaypointAtIndex(int aIndex);
+
+// tied-property getter/setters
+ void setCommand(const char* aCmd);
+ const char* getCommand() const { return ""; }
+
+ const char* getMode() const { return _mode.c_str(); }
+
+ bool getScratchValid() const { return _scratchValid; }
+ double getScratchDistance() const;
+ double getScratchMagBearing() const;
+ double getScratchTrueBearing() const;
+ bool getScratchHasNext() const;
+
+ double getSelectedCourse() const { return _selectedCourse; }
+ void setSelectedCourse(double crs);
+ double getDesiredCourse() const { return _desiredCourse; }
+
+ double getCDIDeflection() const;
+
+ double getLegDistance() const;
+ double getLegCourse() const;
+ double getLegMagCourse() const;
+
+ double getTrueTrack() const { return _last_true_track; }
+ double getMagTrack() const;
+ double getGroundspeedKts() const { return _last_speed_kts; }
+ double getVerticalSpeed() const { return _last_vertical_speed; }
+
+ //bool getLegMode() const { return _mode == "leg"; }
+ //bool getObsMode() const { return _mode == "obs"; }
+
+ const char* getWP0Ident() const;
+ const char* getWP0Name() const;
+
+ const char* getWP1Ident() const;
+ const char* getWP1Name() const;
+
+ double getWP1Distance() const;
+ double getWP1TTW() const;
+ const char* getWP1TTWString() const;
+ double getWP1Bearing() const;
+ double getWP1MagBearing() const;
+ double getWP1CourseDeviation() const;
+ double getWP1CourseErrorNm() const;
+ bool getWP1ToFlag() const;
+ bool getWP1FromFlag() const;
+
+ // true-bearing-error and mag-bearing-error
+
+
+ /**
+ * Tied-properties helper, record nodes which are tied for easy un-tie-ing
+ */
+ template <typename T>
+ void tie(SGPropertyNode* aNode, const char* aRelPath, const SGRawValue<T>& aRawValue)
+ {
+ SGPropertyNode* nd = aNode->getNode(aRelPath, true);
+ _tiedNodes.push_back(nd);
+ nd->tie(aRawValue);
+ }