// gps.hxx - distance-measuring equipment. // Written by David Megginson, started 2003. // // This file is in the Public Domain and comes with no warranty. #ifndef __INSTRUMENTS_GPS_HXX #define __INSTRUMENTS_GPS_HXX 1 #include #include #include #include "Navaids/positioned.hxx" // forward decls class SGRoute; class FGRouteMgr; class FGAirport; class GPSListener; class SGGeodProperty { public: SGGeodProperty() { } void init(SGPropertyNode* base, const char* lonStr, const char* latStr, const char* altStr = NULL); void init(const char* lonStr, const char* latStr, const char* altStr = NULL); void clear(); void operator=(const SGGeod& geod); SGGeod get() const; private: SGPropertyNode_ptr _lon, _lat, _alt; }; /** * Model a GPS radio. * * Input properties: * * /position/longitude-deg * /position/latitude-deg * /position/altitude-ft * /environment/magnetic-variation-deg * /systems/electrical/outputs/gps * /instrumentation/gps/serviceable * * * Output properties: * * /instrumentation/gps/indicated-longitude-deg * /instrumentation/gps/indicated-latitude-deg * /instrumentation/gps/indicated-altitude-ft * /instrumentation/gps/indicated-vertical-speed-fpm * /instrumentation/gps/indicated-track-true-deg * /instrumentation/gps/indicated-track-magnetic-deg * /instrumentation/gps/indicated-ground-speed-kt * * /instrumentation/gps/wp-distance-nm * /instrumentation/gps/wp-bearing-deg * /instrumentation/gps/wp-bearing-mag-deg * /instrumentation/gps/TTW * /instrumentation/gps/course-deviation-deg * /instrumentation/gps/course-error-nm * /instrumentation/gps/to-flag * /instrumentation/gps/odometer * /instrumentation/gps/trip-odometer * /instrumentation/gps/true-bug-error-deg * /instrumentation/gps/magnetic-bug-error-deg */ class GPS : public SGSubsystem { public: GPS (SGPropertyNode *node); GPS (); virtual ~GPS (); virtual void init (); virtual void update (double delta_time_sec); virtual void bind(); virtual void unbind(); private: 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 tuneNavRadioToRefVor() const { return _tuneRadio1ToRefVor; } bool requireHardSurface() const { return _requireHardSurface; } double minRunwayLengthFt() const { return _minRunwayLengthFt; } double getExternalCourse() const; void setExternalCourse(double aCourseDeg); bool cdiDeflectionIsAngular() const { return (_cdiMaxDeflectionNm <= 0.0); } double cdiDeflectionLinearPeg() const { assert(_cdiMaxDeflectionNm > 0.0); return _cdiMaxDeflectionNm; } bool driveAutopilot() const { return _driveAutopilot; } 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; // should GPS automatically tune NAV1 to the reference VOR? bool _tuneRadio1ToRefVor; // minimum runway length to require when filtering double _minRunwayLengthFt; // should we require a hard-surfaced runway when filtering? bool _requireHardSurface; // helpers to tie course-source property const char* getCourseSource() const; void setCourseSource(const char* aPropPath); // property to retrieve the external course from SGPropertyNode_ptr _extCourseSource; double _cdiMaxDeflectionNm; bool _driveAutopilot; }; 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 updateWaypoints(); void updateTrackingBug(); void updateReferenceNavaid(double dt); void referenceNavaidSet(const std::string& aNavaid); void tuneNavRadios(); 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 { return _searchHasNext; } double getSelectedCourse() const { return _selectedCourse; } double getCDIDeflection() const; double getLegDistance() const; double getLegCourse() const; double getLegMagCourse() const; double getAltDistanceRatio() 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 void tie(SGPropertyNode* aNode, const char* aRelPath, const SGRawValue& aRawValue) { SGPropertyNode* nd = aNode->getNode(aRelPath, true); _tiedNodes.push_back(nd); nd->tie(aRawValue); } /// helper, tie the lat/lon/elev of a SGGeod to the named children of aNode void tieSGGeod(SGPropertyNode* aNode, SGGeod& aRef, const char* lonStr, const char* latStr, const char* altStr); /// helper, tie a SGGeod to proeprties, but read-only void tieSGGeodReadOnly(SGPropertyNode* aNode, SGGeod& aRef, const char* lonStr, const char* latStr, const char* altStr); // members SGPropertyNode_ptr _gpsNode; SGPropertyNode_ptr _magvar_node; SGPropertyNode_ptr _serviceable_node; SGPropertyNode_ptr _electrical_node; SGPropertyNode_ptr _tracking_bug_node; SGPropertyNode_ptr _raim_node; SGPropertyNode_ptr _odometer_node; SGPropertyNode_ptr _trip_odometer_node; SGPropertyNode_ptr _true_bug_error_node; SGPropertyNode_ptr _magnetic_bug_error_node; SGPropertyNode_ptr _ref_navaid_id_node; SGPropertyNode_ptr _ref_navaid_bearing_node; SGPropertyNode_ptr _ref_navaid_distance_node; SGPropertyNode_ptr _ref_navaid_mag_bearing_node; SGPropertyNode_ptr _ref_navaid_frequency_node; SGPropertyNode_ptr _ref_navaid_name_node; SGPropertyNode_ptr _route_active_node; SGPropertyNode_ptr _route_current_wp_node; SGPropertyNode_ptr _routeDistanceNm; SGPropertyNode_ptr _routeETE; SGPropertyNode_ptr _routeEditedSignal; SGPropertyNode_ptr _routeFinishedSignal; double _selectedCourse; bool _dataValid; SGGeod _last_pos; bool _lastPosValid; double _last_speed_kts; double _last_true_track; double _last_vertical_speed; std::string _mode; GPSListener* _listener; Config _config; FGRouteMgr* _routeMgr; bool _ref_navaid_set; double _ref_navaid_elapsed; FGPositionedRef _ref_navaid; std::string _name; int _num; SGGeodProperty _position; SGGeod _wp0_position; SGGeod _wp1_position; SGGeod _indicated_pos; std::string _wp0Ident, _wp0Name, _wp1Ident, _wp1Name; double _wp1DistanceM, _wp1TrueBearing; // scratch data SGGeod _scratchPos; SGPropertyNode_ptr _scratchNode; bool _scratchValid; // search data int _searchResultIndex; std::string _searchQuery; FGPositioned::Type _searchType; bool _searchExact; bool _searchOrderByRange; bool _searchResultsCached; FGPositioned::List _searchResults; bool _searchIsRoute; ///< set if 'search' is actually the current route bool _searchHasNext; ///< is there a result after this one? bool _searchNames; ///< set if we're searching names instead of idents // turn data bool _computeTurnData; ///< do we need to update the turn data? bool _anticipateTurn; ///< are we anticipating the next turn or not? bool _inTurn; // is a turn in progress? bool _turnSequenced; // have we sequenced the new leg? double _turnAngle; // angle to turn through, in degrees double _turnStartBearing; // bearing of inbound leg double _turnRadius; // radius of turn in nm SGGeod _turnPt; SGGeod _turnCentre; SGPropertyNode_ptr _realismSimpleGps; ///< should the GPS be simple or realistic? // autopilot drive properties SGPropertyNode_ptr _apTrueHeading; SGPropertyNode_ptr _apTargetAltitudeFt; SGPropertyNode_ptr _apAltitudeLock; std::vector _tiedNodes; }; #endif // __INSTRUMENTS_GPS_HXX