]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/dclgps.hxx
Fix the crashes on mini-panel and panel-reload with the KLN89, by removing the multip...
[flightgear.git] / src / Instrumentation / dclgps.hxx
1 // dclgps.hxx - a class to extend the operation of FG's current GPS
2 // code, and provide support for a KLN89-specific instrument.  It
3 // is envisioned that eventually this file and class will be split
4 // up between current FG code and new KLN89-specific code and removed.
5 //
6 // Written by David Luff, started 2005.
7 //
8 // Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 //
24 // $Id$
25
26 #ifndef _DCLGPS_HXX
27 #define _DCLGPS_HXX
28
29 #include "render_area_2d.hxx"
30 #include <string>
31 #include <list>
32 #include <vector>
33 #include <map>
34
35 #include <Navaids/navrecord.hxx>
36 #include <Navaids/navlist.hxx>
37 #include <Navaids/fixlist.hxx>
38 #include <Airports/simple.hxx>
39 #include <simgear/structure/subsystem_mgr.hxx>
40
41 using namespace std;
42
43 enum GPSDistanceUnits {
44         GPS_DIST_UNITS_NM = 0,
45         GPS_DIST_UNITS_KM
46 };
47
48 enum GPSSpeedUnits {
49         GPS_VEL_UNITS_KT,
50         GPS_VEL_UNITS_KPH
51 };
52
53 enum GPSAltitudeUnits {
54         GPS_ALT_UNITS_FT,
55         GPS_ALT_UNITS_M
56 };
57
58 enum GPSPressureUnits {
59         GPS_PRES_UNITS_IN = 1,
60         GPS_PRES_UNITS_MB,
61         GPS_PRES_UNITS_HP
62 };
63
64 // --------------------- Waypoint / Flightplan stuff -----------------------------
65 // This should be merged with other similar stuff in FG at some point.
66
67 // NOTE - ORDERING IS IMPORTANT HERE - it matches the Bendix-King page ordering!
68 enum GPSWpType {
69         GPS_WP_APT = 0,
70         GPS_WP_VOR,
71         GPS_WP_NDB,
72         GPS_WP_INT,
73         GPS_WP_USR,
74         GPS_WP_VIRT             // Used for virtual waypoints, such as the start of DTO operation.
75 };
76
77 enum GPSAppWpType {
78         GPS_IAF,                // Initial approach fix
79         GPS_IAP,                // Waypoint on approach sequence that isn't any of the others.
80         GPS_FAF,                // Final approach fix
81         GPS_MAP,                // Missed approach point
82         GPS_MAHP,               // Initial missed approach holding point.
83     GPS_HDR,        // A virtual 'waypoint' to represent the approach header in the fpl page
84     GPS_FENCE,      // A virtual 'waypoint' to represent the NO WPT SEQ fence.
85     GPS_APP_NONE    // Not part of the approach sequence - the default.
86 };
87
88 ostream& operator << (ostream& os, GPSAppWpType type);
89
90 struct GPSWaypoint {
91     GPSWaypoint();
92     ~GPSWaypoint();
93         string GetAprId();      // Returns the id with i, f, m or h added if appropriate. (Initial approach fix, final approach fix, etc)
94         string id;
95         float lat;      // Radians
96         float lon;      // Radians
97         GPSWpType type;
98         GPSAppWpType appType;   // only used for waypoints that are part of an approach sequence
99 };
100
101 typedef vector < GPSWaypoint* > gps_waypoint_array;
102 typedef gps_waypoint_array::iterator gps_waypoint_array_iterator;
103 typedef map < string, gps_waypoint_array > gps_waypoint_map;
104 typedef gps_waypoint_map::iterator gps_waypoint_map_iterator;
105 typedef gps_waypoint_map::const_iterator gps_waypoint_map_const_iterator;
106
107 class GPSFlightPlan {
108 public:
109         vector<GPSWaypoint*> waypoints;
110         inline bool IsEmpty() { return(waypoints.size() == 0); }
111 };
112
113 // TODO - probably de-public the internals of the next 2 classes and add some methods!
114 // Instrument approach procedure base class
115 class FGIAP {
116 public:
117         FGIAP();
118         virtual ~FGIAP() = 0;
119 //protected:
120
121         string _id;             // The ID of the airport this approach is for
122         string _name;   // The approach name, eg "VOR/DME OR GPS-B"
123         string _abbrev; // The abbreviation the GPS unit uses - eg "VOR/D" in this instance.  Possibly GPS model specific.
124         string _rwyStr; // The string used to specify the rwy - eg "B" in this instance.
125         bool _precision;        // True for precision approach, false for non-precision.
126 };
127
128 // Non-precision instrument approach procedure
129 class FGNPIAP : public FGIAP {
130 public:
131         FGNPIAP();
132         ~FGNPIAP();
133 //private:
134 public:
135         vector<GPSWaypoint*> _IAF;      // The initial approach fix(es)
136         vector<GPSWaypoint*> _IAP;      // The compulsory waypoints of the approach procedure (may duplicate one of the above).
137                                                                 // _IAP includes the FAF and MAF.
138         vector<GPSWaypoint*> _MAP;      // The missed approach procedure (doesn't include the MAF).
139 };
140
141 typedef vector < FGIAP* > iap_list_type;
142 typedef map < string, iap_list_type > iap_map_type;
143 typedef iap_map_type::iterator iap_map_iterator;
144
145 // ------------------------------------------------------------------------------
146
147 class DCLGPS;
148
149 class GPSPage {
150         
151 public:
152         GPSPage(DCLGPS* parent);
153         virtual ~GPSPage() = 0;
154         virtual void Update(double dt);
155         virtual void Knob1Left1();
156         virtual void Knob1Right1();     
157         virtual void Knob2Left1();
158         virtual void Knob2Right1();     
159         virtual void CrsrPressed();
160         virtual void EntPressed();
161         virtual void ClrPressed();
162         virtual void DtoPressed();
163         virtual void NrstPressed();
164         virtual void AltPressed();
165         virtual void OBSPressed();
166         virtual void MsgPressed();
167         
168         // Sometimes a page needs to maintain state for some return paths,
169         // but change it for others.  The CleanUp function can be used for
170         // changing state for non-ENT return  paths in conjunction with
171         // GPS::_cleanUpPage
172         virtual void CleanUp();
173         
174         // The LooseFocus function is called when a page or subpage looses focus
175         // and allow pages to clean up state that is maintained whilst focus is
176         // retained, but lost on return.
177         virtual void LooseFocus();
178         
179         // Allows pages that display info for a given ID to have it set/get if they implement these functions.
180         virtual void SetId(const string& s);
181         virtual const string& GetId()=0;
182         
183         inline int GetSubPage() { return(_subPage); }
184         
185         inline int GetNSubPages() { return(_nSubPages); }
186         
187         inline const string& GetName() { return(_name); }
188         
189 protected:
190         DCLGPS* _parent;
191         string _name;   // eg. "APT", "NAV" etc
192         int _nSubPages;
193         // _subpage is zero based
194         int _subPage;   // The subpage gets remembered when other pages are displayed
195         string GPSitoa(int n);
196 };
197
198 /*-----------------------------------------------------------------------*/
199
200 typedef vector<GPSPage*> gps_page_list_type;
201 typedef gps_page_list_type::iterator gps_page_list_itr;
202
203 // TODO - merge generic GPS functions instead and split out KLN specific stuff.
204 class DCLGPS : public SGSubsystem {
205         
206         friend class GPSPage;
207         
208 public:
209         DCLGPS(RenderArea2D* instrument);
210         virtual ~DCLGPS() = 0;
211         
212         virtual void draw();
213         
214         virtual void init();
215         virtual void bind();
216         virtual void unbind();
217         virtual void update(double dt);
218
219         // Render string s in display field field at position x, y
220         // WHERE POSITION IS IN CHARACTER UNITS!
221         // zero y at bottom?
222         virtual void DrawText(const string& s, int field, int px, int py, bool bold = false);
223         
224         // Render a char at a given position as above
225         virtual void DrawChar(char c, int field, int px, int py, bool bold = false);
226         
227         virtual void Knob1Right1();
228         virtual void Knob1Left1();
229         virtual void Knob2Right1();
230         virtual void Knob2Left1();
231         virtual void CrsrPressed();
232         virtual void EntPressed();
233         virtual void ClrPressed();
234         virtual void DtoPressed();
235         virtual void NrstPressed();
236         virtual void AltPressed();
237         virtual void OBSPressed();
238         virtual void MsgPressed();
239         
240         // Set the number of fields
241         inline void SetNumFields(int n) { _nFields = (n > _maxFields ? _maxFields : (n < 1 ? 1 : n)); }
242         
243         // Set Units
244         // m if true, ft if false
245         inline void SetAltUnitsSI(bool b) { _altUnits = (b ? GPS_ALT_UNITS_M : GPS_ALT_UNITS_FT); }
246         // Returns true if alt units are SI (m), false if ft
247         inline bool GetAltUnitsSI() { return(_altUnits == GPS_ALT_UNITS_M ? true : false); }
248         // km and k/h if true, nm and kt if false
249         inline void SetDistVelUnitsSI(bool b) { _distUnits = (b ? GPS_DIST_UNITS_KM : GPS_DIST_UNITS_NM); _velUnits = (b ? GPS_VEL_UNITS_KPH : GPS_VEL_UNITS_KT); }
250         // Returns true if dist/vel units are SI
251         inline bool GetDistVelUnitsSI() { return(_distUnits == GPS_DIST_UNITS_KM && _velUnits == GPS_VEL_UNITS_KPH ? true : false); }
252         // Set baro units - 1 = in, 2 = mB, 3 = hP   Wrapping if for the convienience of the GPS setter.
253         void SetBaroUnits(int n, bool wrap = false);
254         // Get baro units: 1 = in, 2 = mB, 3 = hP
255         inline int GetBaroUnits() { return((int)_baroUnits); }
256         
257         // It is expected that specific GPS units will override these functions.
258         // Increase the CDI full-scale deflection (ie. increase the nm per dot) one (GPS unit dependent) increment.  Wraps if necessary (GPS unit dependent).
259         virtual void CDIFSDIncrease();
260         // Ditto for decrease the distance per dot
261         virtual void CDIFSDDecrease();
262         
263         // Host specifc
264         ////inline void SetOverlays(Overlays* overlays) { _overlays = overlays; }
265         
266         virtual void CreateDefaultFlightPlans();
267         
268         void SetOBSFromWaypoint();
269         
270         inline GPSWaypoint* GetActiveWaypoint() { return &_activeWaypoint; }
271         // Get the (zero-based) position of the active waypoint in the active flightplan
272         // Returns -1 if no active waypoint.
273         int GetActiveWaypointIndex();
274         // Ditto for an arbitrary waypoint id
275         int GetWaypointIndex(const string& id);
276         
277         // Returns meters
278         inline float GetDistToActiveWaypoint() { return _dist2Act; }
279         // Returns degrees (magnetic)
280         float GetHeadingToActiveWaypoint();
281         // Returns degrees (magnetic)
282         float GetHeadingFromActiveWaypoint();
283         // Get the time to the active waypoint in seconds.
284         // Returns -1 if groundspeed < 30 kts
285         double GetTimeToActiveWaypoint();
286         // Get the time to the final waypoint in seconds.
287         // Returns -1 if groundspeed < 30 kts
288         double GetETE();
289         // Get the time to a given waypoint (spec'd by ID) in seconds.
290         // returns -1 if groundspeed is less than 30kts.
291         // If the waypoint is an unreached part of the active flight plan the time will be via each leg.
292         // otherwise it will be a direct-to time.
293         double GetTimeToWaypoint(const string& id);
294         
295         // Return true if waypoint alerting is occuring
296         inline bool GetWaypointAlert() const { return(_waypointAlert); }
297         // Return true if in OBS mode
298         inline bool GetOBSMode() const { return(_obsMode); }
299         // Return true if in Leg mode
300         inline bool GetLegMode() const { return(!_obsMode); }
301         
302         // Clear a flightplan
303         void ClearFlightPlan(int n);
304         void ClearFlightPlan(GPSFlightPlan* fp);
305         
306         // Returns true if an approach is loaded/armed/active in the active flight plan
307         inline bool ApproachLoaded() const { return(_approachLoaded); }
308         inline bool GetApproachArm() const { return(_approachArm); }
309         inline bool GetApproachActive() const { return(_approachActive); }
310         double GetCDIDeflection() const;
311         inline bool GetToFlag() const { return(_headingBugTo); }
312         
313         // Initiate Direct To operation to the supplied ID.
314         void DtoInitiate(const string& id);
315         // Cancel Direct To operation
316         void DtoCancel();
317         
318 protected:
319         // Maximum number of display fields for this device
320         int _maxFields;
321         // Current number of on-screen fields
322         int _nFields;
323         // Full x border
324         int _xBorder;
325         // Full y border
326         int _yBorder;
327         // Lower (y) border per field
328         int _yFieldBorder[4];
329         // Left (x) border per field
330         int _xFieldBorder[4];
331         // Field start in x dir (border is part of field since it is the normal char border - sometimes map mode etc draws in it)
332         int _xFieldStart[4];
333         // Field start in y dir (for completeness - KLN89 only has vertical divider.
334         int _yFieldStart[4];
335         
336         // The number of pages on the cyclic knob control
337         unsigned int _nPages;
338         // The current page we're on (Not sure how this ties in with extra pages such as direct or nearest).
339         unsigned int _curPage;
340         
341         // 2D rendering area
342         RenderArea2D* _instrument;
343         
344         // The actual pages
345         gps_page_list_type _pages;
346         
347         // The currently active page
348         GPSPage* _activePage;
349         // And a facility to save the immediately preceeding active page
350         GPSPage* _lastActivePage;
351         
352         // Units
353         GPSSpeedUnits _velUnits;
354         GPSDistanceUnits _distUnits;
355         GPSPressureUnits _baroUnits;
356         GPSAltitudeUnits _altUnits;
357         
358         // CDI full-scale deflection, specified either as an index into a vector of values (standard values) or as a double precision float (intermediate values).
359         // This will influence how an externally driven CDI will display as well as the NAV1 page.
360         // Hence the variables are located here, not in the nav page class.
361         vector<float> _cdiScales;
362         unsigned int _currentCdiScaleIndex;
363         bool _cdiScaleTransition;               // Set true when the floating CDI value is used during transitions
364         double _currentCdiScale;        // The floating value to use.
365         unsigned int _targetCdiScaleIndex;      // The target indexed value to attain during a transition.
366         unsigned int _sourceCdiScaleIndex;      // The source indexed value during a transition - so we know which way we're heading!
367         // Timers to handle the transitions - not sure if we need these.
368         double _apprArmTimer;
369         double _apprActvTimer;
370         double _cdiTransitionTime;      // Time for transition to occur in - normally 30sec but may be quicker if time to FAF < 30sec?
371         // 
372         
373         // Data and lookup functions
374         // All waypoints mapped by id.
375         gps_waypoint_map _waypoints;
376 private:
377         // Worker function for the below.
378         const GPSWaypoint* ActualFindFirstById(const string& id, bool exact = false);
379 protected:
380         // Find first of any type of waypoint by id.  (TODO - Possibly we should return multiple waypoints here).
381         const GPSWaypoint* FindFirstById(const string& id, bool &multi, bool exact = false); 
382         FGNavRecord* FindFirstVorById(const string& id, bool &multi, bool exact = false);
383         FGNavRecord* FindFirstNDBById(const string& id, bool &multi, bool exact = false);
384         const FGAirport* FindFirstAptById(const string& id, bool &multi, bool exact = false);
385         const FGFix* FindFirstIntById(const string& id, bool &multi, bool exact = false);
386         // Find the closest VOR to a position in RADIANS.
387         FGNavRecord* FindClosestVor(double lat_rad, double lon_rad);
388
389         // Position, orientation and velocity.
390         // These should be read from FG's built-in GPS logic if possible.
391         // Use the property node pointers below to do this.
392     SGPropertyNode_ptr _lon_node;
393     SGPropertyNode_ptr _lat_node;
394     SGPropertyNode_ptr _alt_node;
395         SGPropertyNode_ptr _grnd_speed_node;
396         SGPropertyNode_ptr _true_track_node;
397         SGPropertyNode_ptr _mag_track_node;
398         // Present position. (Radians)
399         double _lat, _lon;
400         // Present altitude (ft). (Yuk! but it saves converting ft->m->ft every update).
401         double _alt;
402         // Reported position as measured by GPS.  For now this is the same
403         // as present position, but in the future we might want to model
404         // GPS lat and lon errors.
405         // Note - we can depriciate _gpsLat and _gpsLon if we implement error handling in FG
406         // gps code and not our own.
407         double _gpsLat, _gpsLon;  //(Radians)
408         // Hack - it seems that the GPS gets initialised before FG's initial position is properly set.
409         // By checking for abnormal slew in the position we can force a re-initialisation of active flight
410         // plan leg and anything else that might be affected.
411         // TODO - sort FlightGear's initialisation order properly!!!
412         double _checkLat, _checkLon;    // (Radians)
413         double _groundSpeed_ms; // filtered groundspeed (m/s)
414         double _groundSpeed_kts;        // ditto in knots
415         double _track;                  // filtered true track (degrees)
416         double _magTrackDeg;    // magnetic track in degrees calculated from true track above
417         
418         // _navFlagged is set true when GPS navigation is either not possible or not logical.
419         // This includes not receiving adequate signals, and not having an active flightplan entered.
420         bool _navFlagged;
421         
422         // Positional functions copied from ATCutils that might get replaced
423         // INPUT in RADIANS, returns DEGREES!
424         // Magnetic
425         double GetMagHeadingFromTo(double latA, double lonA, double latB, double lonB);
426         // True
427         //double GetHeadingFromTo(double latA, double lonA, double latB, double lonB);
428         
429         // Given two positions (lat & lon in RADIANS), get the HORIZONTAL separation (in meters)
430         //double GetHorizontalSeparation(double lat1, double lon1, double lat2, double lon2);
431         
432         // Proper great circle positional functions from The Aviation Formulary
433         // Returns distance in Nm, input in RADIANS.
434         double GetGreatCircleDistance(double lat1, double lon1, double lat2, double lon2) const;
435         
436         // Input in RADIANS, output in DEGREES.
437         // True
438         double GetGreatCircleCourse(double lat1, double lon1, double lat2, double lon2) const;
439         
440         // Return a position on a radial from wp1 given distance d (nm) and magnetic heading h (degrees)
441         // Note that d should be less that 1/4 Earth diameter!
442         GPSWaypoint GetPositionOnMagRadial(const GPSWaypoint& wp1, double d, double h);
443         
444         // Return a position on a radial from wp1 given distance d (nm) and TRUE heading h (degrees)
445         // Note that d should be less that 1/4 Earth diameter!
446         GPSWaypoint GetPositionOnRadial(const GPSWaypoint& wp1, double d, double h);
447         
448         // Calculate the current cross-track deviation in nm.
449         // Returns zero if a sensible value cannot be calculated.
450         double CalcCrossTrackDeviation() const;
451         
452         // Calculate the cross-track deviation between 2 arbitrary waypoints in nm.
453         // Returns zero if a sensible value cannot be calculated.
454         double CalcCrossTrackDeviation(const GPSWaypoint& wp1, const GPSWaypoint& wp2) const;
455         
456         // Flightplans
457         // GPS can have up to _maxFlightPlans flightplans stored, PLUS an active FP which may or my not be one of the stored ones.
458         // This is from KLN89, but is probably not far off the mark for most if not all GPS.
459         vector<GPSFlightPlan*> _flightPlans;
460         unsigned int _maxFlightPlans;
461         GPSFlightPlan* _activeFP;
462         
463         // Modes of operation.
464         // This is currently somewhat Bendix-King specific, but probably applies fundamentally to other units as well
465         // Mode defaults to leg, but is OBS if _obsMode is true.
466         bool _obsMode;
467         // _dto is set true for DTO operation
468         bool _dto;
469         // In leg mode, we need to know if we are displaying a from and to waypoint, or just the to waypoint (eg. when OBS mode is cancelled).
470         bool _fullLegMode;
471         // In OBS mode we need to know the set OBS heading
472         int _obsHeading;
473         
474         // Operational variables
475         GPSWaypoint _activeWaypoint;
476         GPSWaypoint _fromWaypoint;
477         float _dist2Act;
478         float _crosstrackDist;  // UNITS ??????????
479         double _eta;    // ETA in SECONDS to active waypoint.
480         // Desired track for active leg, true and magnetic, in degrees
481         double _dtkTrue, _dtkMag;
482         bool _headingBugTo;             // Set true when the heading bug is TO, false when FROM.
483         bool _waypointAlert;    // Set true when waypoint alerting is happening. (This is a variable NOT a user-setting).
484         bool _departed;         // Set when groundspeed first exceeds 30kts.
485         string _departureTimeString;    // Ditto.
486         double _elapsedTime;    // Elapsed time in seconds since departure
487         
488         // Configuration that affects flightplan operation
489         bool _turnAnticipationEnabled;
490         
491         // Configuration that affects general operation
492         bool _suaAlertEnabled;          // Alert user to potential SUA entry
493         bool _altAlertEnabled;          // Alert user to min safe alt violation
494         
495         // Magvar stuff.  Might get some of this stuff (such as time) from FG in future.
496         SGTime* _time;
497         
498         list<string> _messageStack;
499         
500         virtual void CreateFlightPlan(GPSFlightPlan* fp, vector<string> ids, vector<GPSWpType> wps);
501         
502         // Orientate the GPS unit to a flightplan - ie. figure out from current position
503         // and possibly orientation which leg of the FP we are on.
504         virtual void OrientateToFlightPlan(GPSFlightPlan* fp);
505         
506         // Ditto for active fp.  Probably all we need really!
507         virtual void OrientateToActiveFlightPlan();
508         
509         int _cleanUpPage;       // -1 => no cleanup required.
510         
511         // IAP stuff
512         iap_map_type _np_iap;   // Non-precision approaches
513         iap_map_type _pr_iap;   // Precision approaches
514         bool _approachLoaded;   // Set true when an approach is loaded in the active flightplan
515         bool _approachArm;              // Set true when in approach-arm mode
516         bool _approachReallyArmed;      // Apparently, approach-arm mode can be set from an external GPS-APR switch outside 30nm from airport,
517                                                                 // but the CDI scale change doesn't happen until 30nm from airport.  Bizarre that it can be armed without
518                                                                 // the scale change, but it's in the manual...
519         bool _approachActive;   // Set true when in approach-active mode
520         GPSFlightPlan* _approachFP;     // Current approach - not necessarily loaded.
521         string _approachID;             // ID of the airport we have an approach loaded for - bit of a hack that can hopefully be removed in future.
522         // More hackery since we aren't actually storing an approach class... Doh!
523         string _approachAbbrev;
524         string _approachRwyStr;
525 };
526
527 #endif  // _DCLGPS_HXX