]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/KLN89/kln89_page_nav.cxx
Vassilii Khachaturov:
[flightgear.git] / src / Instrumentation / KLN89 / kln89_page_nav.cxx
1 // kln89_page_*.[ch]xx - this file is one of the "pages" that
2 //                       are used in the KLN89 GPS unit simulation. 
3 //
4 // Written by David Luff, started 2005.
5 //
6 // Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24 #include "kln89_page_nav.hxx"
25
26 KLN89NavPage::KLN89NavPage(KLN89* parent) 
27 : KLN89Page(parent) {
28         _nSubPages = 4;
29         _subPage = 0;
30         _name = "NAV";
31         _posFormat = 0;         // Check - should this default to ref from waypoint?
32         _vnv = 0;
33         _nav4DataSnippet = 0;
34         _cdiFormat = 0;
35         _menuActive = false;
36         _menuPos = 0;
37         _suspendAVS = false;
38 }
39
40 KLN89NavPage::~KLN89NavPage() {
41 }
42
43 void KLN89NavPage::Update(double dt) {
44         GPSFlightPlan* fp = ((KLN89*)_parent)->_activeFP;
45         GPSWaypoint* awp = _parent->GetActiveWaypoint();
46         bool crsr = (_kln89->_mode == KLN89_MODE_CRSR);
47         bool blink = _kln89->_blink;
48         double lat = _kln89->_gpsLat * SG_RADIANS_TO_DEGREES;
49         double lon = _kln89->_gpsLon * SG_RADIANS_TO_DEGREES;
50         
51         if(0 == _subPage) {
52                 if(_kln89->_navFlagged) {
53                         _kln89->DrawText(">    F L A G", 2, 0, 2);
54                         _kln89->DrawText("DTK ---  TK ---", 2, 0, 1);
55                         _kln89->DrawText(">--- To    --:--", 2, 0, 0);
56                         _kln89->DrawSpecialChar(0, 2, 7, 1);
57                         _kln89->DrawSpecialChar(0, 2, 15, 1);
58                         _kln89->DrawSpecialChar(0, 2, 4, 0);
59                         _kln89->DrawSpecialChar(1, 2, 3, 2);
60                         _kln89->DrawSpecialChar(1, 2, 4, 2);
61                         _kln89->DrawSpecialChar(1, 2, 6, 2);
62                         _kln89->DrawSpecialChar(1, 2, 10, 2);
63                         _kln89->DrawSpecialChar(1, 2, 12, 2);
64                         _kln89->DrawSpecialChar(1, 2, 13, 2);
65                 } else {
66                         if(_kln89->_dto) {
67                                 _kln89->DrawDTO(2, 7, 3);
68                         } else {
69                                 if(!(_kln89->_waypointAlert && _kln89->_blink)) {
70                                         _kln89->DrawSpecialChar(3, 2, 8, 3);
71                                 }
72                         }
73                         _kln89->DrawText(awp->id, 2, 10, 3);
74                         if(!_kln89->_dto && !_kln89->_obsMode && !_kln89->_fromWaypoint.id.empty()) {
75                                 _kln89->DrawText(_kln89->_fromWaypoint.id, 2, 1, 3);
76                         }
77                         if(!(crsr && blink && _uLinePos == 1)) {
78                                 if(_cdiFormat == 0) {
79                                         _kln89->DrawCDI();
80                                 } else if(_cdiFormat == 1) {
81                                         _kln89->DrawText("Fly", 2, 2, 2);
82                                         double x = _kln89->CalcCrossTrackDeviation();
83                                         // TODO - check the R/L from sign of x below - I *think* it holds but not sure!
84                                         // Note also that we're setting Fly R or L based on the aircraft
85                                         // position only, not the heading.  Not sure if this is correct or not.
86                                         _kln89->DrawText(x < 0.0 ? "R" : "L", 2, 6, 2);
87                                         char buf[6];
88                                         int n;
89                                         x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
90                                         if(x < 1.0) {
91                                                 n = snprintf(buf, 6, "%0.2f", x);
92                                         } else if(x < 100.0) {
93                                                 n = snprintf(buf, 6, "%0.1f", x);
94                                         } else {
95                                                 n = snprintf(buf, 6, "%i", (int)(x+0.5));
96                                         }
97                                         _kln89->DrawText((string)buf, 2, 13-n, 2);
98                                         _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 13, 2);
99                                 } else {
100                                         _kln89->DrawText("CDI Scale:", 2, 1, 2);
101                                         double d = _kln89->_cdiScales[_kln89->_currentCdiScaleIndex] * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001);
102                                         char buf[5];
103                                         string s;
104                                         if(d >= 1.0) {
105                                                 snprintf(buf, 4, "%2.1f", d);
106                                                 s = buf;
107                                         } else {
108                                                 snprintf(buf, 5, "%2.2f", d);
109                                                 // trim the leading zero
110                                                 s = buf;
111                                                 s = s.substr(1, s.size() - 1);
112                                         }
113                                         _kln89->DrawText(s, 2, 11, 2);
114                                         _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 14, 2);
115                                 }
116                         }
117                         _kln89->DrawChar('>', 2, 0, 2);
118                         _kln89->DrawChar('>', 2, 0, 0);
119                         if(crsr) {
120                                 if(_uLinePos == 1) _kln89->Underline(2, 1, 2, 15);
121                                 else if(_uLinePos == 2) _kln89->Underline(2, 1, 0, 9);
122                         }
123                         // Desired and actual magnetic track
124                         if(!_kln89->_obsMode) {
125                                 _kln89->DrawText("DTK", 2, 0, 1);
126                                 _kln89->DrawHeading((int)_kln89->_dtkMag, 2, 7, 1);
127                         }
128                         _kln89->DrawText("TK", 2, 9, 1);
129                         if(_kln89->_groundSpeed_ms > 3) {       // about 6 knots, don't know exactly what value to disable track
130                                 // The trouble with relying on FG gps's track value is we don't know when it's valid.
131                                 _kln89->DrawHeading((int)_kln89->_magTrackDeg, 2, 15, 1);
132                         } else {
133                                 _kln89->DrawText("---", 2, 12, 1);
134                                 _kln89->DrawSpecialChar(0, 2, 15, 1);
135                         }
136                         
137                         // Radial to/from active waypoint.
138                         // TODO - Not sure if this either is or should be true or mag!!!!!!!
139                         if(!(crsr && blink && _uLinePos == 2)) {
140                                 if(0 == _vnv) {
141                                         _kln89->DrawHeading((int)_kln89->GetHeadingToActiveWaypoint(), 2, 4, 0);
142                                         _kln89->DrawText("To", 2, 5, 0);
143                                 } else if(1 == _vnv) {
144                                         _kln89->DrawHeading((int)_kln89->GetHeadingFromActiveWaypoint(), 2, 4, 0);
145                                         _kln89->DrawText("Fr", 2, 5, 0);
146                                 } else {
147                                         _kln89->DrawText("Vnv Off", 2, 1, 0);
148                                 }
149                         }
150                         // It seems that the floating point groundspeed must be at least 30kt
151                         // for an ETA to be calculated.  Note that this means that (integer) 30kt
152                         // can appear in the frame 1 display both with and without an ETA displayed.
153                         // TODO - need to switch off track (and heading bug change) based on instantaneous speed as well
154                         // since the long gps lag filter means we can still be displaying when stopped on ground.
155                         if(_kln89->_groundSpeed_kts > 30.0) {
156                                 // Assuming eta display is always hh:mm
157                                 // Does it ever switch to seconds when close?
158                                 if(_kln89->_eta / 3600.0 > 100.0) {
159                                         // More that 100 hours ! - Doesn't fit.
160                                         _kln89->DrawText("--:--", 2, 11, 0);
161                                 } else {
162                                         _kln89->DrawTime(_kln89->_eta, 2, 15, 0);
163                                 }
164                         } else {
165                                 _kln89->DrawText("--:--", 2, 11, 0);
166                         }
167                 }
168         } else if(1 == _subPage) {
169                 // Present position
170                 _kln89->DrawChar('>', 2, 1, 3);
171                 if(!(crsr && blink && _uLinePos == 1)) _kln89->DrawText("PRESENT POSN", 2, 2, 3);
172                 if(crsr && _uLinePos == 1) _kln89->Underline(2, 2, 3, 12);
173                 if(0 == _posFormat) {
174                         // Lat/lon
175                         _kln89->DrawLatitude(lat, 2, 3, 1);
176                         _kln89->DrawLongitude(lon, 2, 3, 0);
177                 } else {
178                         // Ref from wp - defaults to nearest vor (and resets to default when page left and re-entered).
179                 }
180         } else if(2 == _subPage) {
181                 _kln89->DrawText("Time", 2, 0, 3);
182                 // TODO - hardwired to UTC at the moment
183                 _kln89->DrawText("UTC", 2, 6, 3);
184                 string th = fgGetString("/instrumentation/clock/indicated-hour");
185                 string tm = fgGetString("/instrumentation/clock/indicated-min");
186                 if(th.size() == 1) th = "0" + th;
187                 if(tm.size() == 1) tm = "0" + tm;
188                 _kln89->DrawText(th + tm, 2, 11, 3);
189                 _kln89->DrawText("Depart", 2, 0, 2);
190                 _kln89->DrawText(_kln89->_departureTimeString, 2, 11, 2);
191                 _kln89->DrawText("ETA", 2, 0, 1);
192                 if(_kln89->_departed) {
193                         /* Rules of ETA waypoint are:
194                          If the active waypoint is part of the active flightplan, then display
195                          the ETA to the final (destination) waypoint of the active flightplan.
196                          If the active waypoint is not part of the active flightplan, then
197                          display the ETA to the active waypoint. */
198                         // TODO - implement the above properly - we haven't below!
199                         string wid = "";
200                         if(fp->waypoints.size()) {
201                                 wid = fp->waypoints[fp->waypoints.size() - 1]->id;
202                         } else if(awp) {
203                                 wid = awp->id;
204                         }
205                         if(!wid.empty()) {
206                                 _kln89->DrawText(wid, 2, 4, 1);
207                                 double tsec = _kln89->GetTimeToWaypoint(wid);
208                                 if(tsec < 0.0) {
209                                         _kln89->DrawText("----", 2, 11, 1);
210                                 } else {
211                                         int etah = (int)tsec / 3600;
212                                         int etam = ((int)tsec - etah * 3600) / 60;
213                                         etah += atoi(fgGetString("/instrumentation/clock/indicated-hour"));
214                                         etam += atoi(fgGetString("/instrumentation/clock/indicated-min"));
215                                         while(etam > 59) {
216                                                 etam -= 60;
217                                                 etah += 1;
218                                         }
219                                         while(etah > 23) {
220                                                 etah -= 24;
221                                         }
222                                         char buf[6];
223                                         int n = snprintf(buf, 6, "%02i%02i", etah, etam);
224                                         _kln89->DrawText((string)buf, 2, 15-n, 1);
225                                 }
226                         } else {
227                                 _kln89->DrawText("----", 2, 11, 1);
228                         }
229                 } else {
230                         _kln89->DrawText("----", 2, 11, 1);
231                 }
232                 _kln89->DrawText("Flight", 2, 0, 0);
233                 if(_kln89->_departed) {
234                         int eh = (int)_kln89->_elapsedTime / 3600;
235                         int em = ((int)_kln89->_elapsedTime - eh * 3600) / 60;
236                         char buf[6];
237                         int n = snprintf(buf, 6, "%i:%02i", eh, em);
238                         _kln89->DrawText((string)buf, 2, 15-n, 0);
239                 } else {
240                         _kln89->DrawText("-:--", 2, 11, 0);
241                 }
242         } else {
243                 // The moving map page the core KLN89 class draws this.
244                 if(_kln89->_mapOrientation == 2 && _kln89->_groundSpeed_kts < 2) {
245                         // Don't draw it if in track up mode and groundspeed < 2kts, as per real-life unit.
246                 } else {
247                         _kln89->DrawMap(!_suspendAVS);
248                 }
249                 // Now draw any annotation over it.
250                 int scale = KLN89MapScales[_kln89->_mapScaleUnits][_kln89->_mapScaleIndex];
251                 string scle_str = GPSitoa(scale);
252                 if(crsr) {
253                         if(_menuActive) {
254                                 // Draw a background quad to encompass on/off for the first three at 'off' length
255                                 _kln89->DrawMapQuad(28, 9, 48, 36, true);
256                                 _kln89->DrawMapText("SUA:", 1, 27, true);
257                                 if(!(_menuPos == 0 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawSUA ? "on" : "off"), 29, 27, true);
258                                 if(_menuPos == 0) _kln89->DrawLine(28, 27, 48, 27);
259                                 _kln89->DrawMapText("VOR:", 1, 18, true);
260                                 if(!(_menuPos == 1 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawVOR ? "on" : "off"), 29, 18, true);
261                                 if(_menuPos == 1) _kln89->DrawLine(28, 18, 48, 18);
262                                 _kln89->DrawMapText("APT:", 1, 9, true);
263                                 if(!(_menuPos == 2 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawApt ? "on" : "off"), 29, 9, true);
264                                 if(_menuPos == 2) _kln89->DrawLine(28, 9, 48, 9);
265                                 _kln89->DrawMapQuad(0, 0, 27, 8, true);
266                                 if(!(_menuPos == 3 && _kln89->_blink)) {
267                                         if(_kln89->_mapOrientation == 0) {
268                                                 _kln89->DrawMapText("N", 1, 0, true);
269                                                 _kln89->DrawMapUpArrow(7, 1);
270                                         } else if(_kln89->_mapOrientation == 1) {
271                                                 _kln89->DrawMapText("DTK", 1, 0, true);
272                                                 _kln89->DrawMapUpArrow(21, 1);
273                                         } else {
274                                                 // Don't bother with heading up for now!
275                                                 _kln89->DrawMapText("TK", 1, 0, true);
276                                                 _kln89->DrawMapUpArrow(14, 1);
277                                         }
278                                 }
279                                 if(_menuPos == 3) _kln89->DrawLine(0, 0, 27, 0);
280                         } else {
281                                 if(_uLinePos == 2) {
282                                         if(!_kln89->_blink) {
283                                                 _kln89->DrawMapText("Menu?", 1, 9, true);
284                                                 _kln89->DrawEnt();
285                                                 _kln89->DrawLine(0, 9, 34, 9);
286                                         } else {
287                                                 _kln89->DrawMapQuad(0, 9, 34, 17, true);
288                                         }
289                                 } else {
290                                         _kln89->DrawMapText("Menu?", 1, 9, true);
291                                 }
292                                 // right-justify the scale when _uLinePos == 3
293                                 if(!(_uLinePos == 3 && _kln89->_blink)) _kln89->DrawMapText(scle_str, (_uLinePos == 3 ? 29 - (scle_str.size() * 7) : 1), 0, true);
294                                 if(_uLinePos == 3) _kln89->DrawLine(0, 0, 27, 0);
295                         }
296                 } else {
297                         // Just draw the scale
298                         _kln89->DrawMapText(scle_str, 1, 0, true);
299                 }
300                 // And do part of the field 1 update, since NAV 4 is a special case for the last line.
301                 _kln89->DrawChar('>', 1, 0, 0);
302                 if(crsr && _uLinePos == 1) _kln89->Underline(1, 1, 0, 5);
303                 if(!(crsr && _uLinePos == 1 && _kln89->_blink)) {
304                         if(_kln89->_obsMode && _nav4DataSnippet == 0) _nav4DataSnippet = 1;
305                         double tsec;
306                         switch(_nav4DataSnippet) {
307                         case 0:
308                                 // DTK
309                                 _kln89->DrawLabel("DTK", -39, 6); 
310                                 // TODO - check we have an active FP / dtk and draw dashes if not.
311                                 char buf0[4];
312                                 snprintf(buf0, 4, "%03i", (int)(_kln89->_dtkMag));
313                                 _kln89->DrawText((string)buf0, 1, 3, 0);
314                                 break;
315                         case 1:
316                                 // groundspeed
317                                 _kln89->DrawSpeed(_kln89->_groundSpeed_kts, 1, 5, 0);
318                                 break;
319                         case 2:
320                                 // ETE
321                                 tsec = _kln89->GetETE();
322                                 if(tsec < 0.0) {
323                                         _kln89->DrawText("--:--", 1, 1, 0);
324                                 } else {
325                                         int eteh = (int)tsec / 3600;
326                                         int etem = ((int)tsec - eteh * 3600) / 60;
327                                         char buf[6];
328                                         int n = snprintf(buf, 6, "%02i:%02i", eteh, etem);
329                                         _kln89->DrawText((string)buf, 1, 6-n, 0);
330                                 }
331                                 break;
332                         case 3:
333                                 // Cross-track correction
334                                 double x = _kln89->CalcCrossTrackDeviation();
335                                 if(x < 0.0) {
336                                         _kln89->DrawSpecialChar(3, 1, 5, 0);
337                                 } else {
338                                         _kln89->DrawSpecialChar(7, 1, 5, 0);
339                                 }
340                                 char buf3[6];
341                                 int n;
342                                 x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
343                                 if(x < 1.0) {
344                                         n = snprintf(buf3, 6, "%0.2f", x);
345                                 } else if(x < 100.0) {
346                                         n = snprintf(buf3, 6, "%0.1f", x);
347                                 } else {
348                                         n = snprintf(buf3, 6, "%i", (int)(x+0.5));
349                                 }
350                                 _kln89->DrawText((string)buf3, 1, 5-n, 0);
351                                 break;
352                         }
353                 }
354         }
355         
356         KLN89Page::Update(dt);
357 }
358
359 void KLN89NavPage::LooseFocus() {
360         _suspendAVS = false;
361 }
362
363 void KLN89NavPage::CrsrPressed() {
364         if(_kln89->_mode == KLN89_MODE_DISP) {
365                 // Crsr just switched off
366                 _menuActive = false;
367         } else {
368                 // Crsr just switched on
369                 if(_subPage < 3) {
370                         _uLinePos = 1;
371                 } else {
372                         _uLinePos = 3;
373                 }
374         }
375 }
376
377 void KLN89NavPage::EntPressed() {
378         if(_kln89->_mode == KLN89_MODE_CRSR) {
379                 if(_subPage == 3 && _uLinePos == 2 && !_menuActive) {
380                         _menuActive = true;
381                         _menuPos = 0;
382                         _suspendAVS = false;
383                 }
384         }
385 }
386
387 void KLN89NavPage::ClrPressed() {
388         if(_kln89->_mode == KLN89_MODE_CRSR) {
389                 if(_subPage == 0) {
390                         if(_uLinePos == 1) {
391                                 _cdiFormat++;
392                                 if(_cdiFormat > 2) _cdiFormat = 0;
393                         } else if(_uLinePos == 2) {
394                                 _vnv++;
395                                 if(_vnv > 2) _vnv = 0;
396                         }
397                 }
398                 if(_subPage == 3) {
399                         if(_uLinePos > 1) {
400                                 _suspendAVS = !_suspendAVS;
401                                 _menuActive = false;
402                         } else if(_uLinePos == 1) {
403                                 _nav4DataSnippet++;
404                                 if(_nav4DataSnippet > 3) _nav4DataSnippet = 0;
405                         }
406                 }
407         } else {
408                 if(_subPage == 3) {
409                         _suspendAVS = !_suspendAVS;
410                 }
411         }
412 }
413
414 void KLN89NavPage::Knob1Left1() {
415         if(_kln89->_mode == KLN89_MODE_CRSR) {
416                 if(!(_subPage == 3 && _menuActive)) {
417                         if(_uLinePos > 0) _uLinePos--;
418                 } else {
419                         if(_menuPos > 0) _menuPos--;
420                 }
421         }
422 }
423
424 void KLN89NavPage::Knob1Right1() {
425         if(_kln89->_mode == KLN89_MODE_CRSR) {
426                 if(_subPage < 2) {
427                         if(_uLinePos < 2) _uLinePos++;
428                 } else if(_subPage == 2) {
429                         _uLinePos = 1;
430                 } else {
431                         // NAV 4 - this is complicated by whether the menu is displayed or not.
432                         if(_menuActive) {
433                                 if(_menuPos < 3) _menuPos++;
434                         } else {
435                                 if(_uLinePos < 3) _uLinePos++;
436                         }
437                 }
438         }
439 }
440
441 void KLN89NavPage::Knob2Left1() {
442         if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
443                 KLN89Page::Knob2Left1();
444                 return;
445         }
446         if(_subPage == 0) {
447                 if(_uLinePos == 1 && _cdiFormat == 2) {
448                         _kln89->CDIFSDIncrease();
449                 }
450         } else if(_subPage == 3) {
451                 if(_menuActive) {
452                         if(_menuPos == 0) {
453                                 _kln89->_drawSUA = !_kln89->_drawSUA;
454                         } else if(_menuPos == 1) {
455                                 _kln89->_drawVOR = !_kln89->_drawVOR;
456                         } else if(_menuPos == 2) {
457                                 _kln89->_drawApt = !_kln89->_drawApt;
458                         } else {
459                                 if(_kln89->_mapOrientation == 0) {
460                                         // Don't allow heading up for now
461                                         _kln89->_mapOrientation = 2;
462                                 } else {
463                                         _kln89->_mapOrientation--;
464                                 }
465                                 _kln89->UpdateMapHeading();
466                         }
467                 } else if(_uLinePos == 3) {
468                         // TODO - add AUTO
469                         if(_kln89->_mapScaleIndex == 0) {
470                                 _kln89->_mapScaleIndex = 20;
471                         } else {
472                                 _kln89->_mapScaleIndex--;
473                         }
474                 }
475         }
476 }
477
478 void KLN89NavPage::Knob2Right1() {
479         if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
480                 KLN89Page::Knob2Right1();
481                 return;
482         }
483         if(_subPage == 0) {
484                 if(_uLinePos == 1 && _cdiFormat == 2) {
485                         _kln89->CDIFSDDecrease();
486                 }
487         } else if(_subPage == 3) {
488                 if(_menuActive) {
489                         if(_menuPos == 0) {
490                                 _kln89->_drawSUA = !_kln89->_drawSUA;
491                         } else if(_menuPos == 1) {
492                                 _kln89->_drawVOR = !_kln89->_drawVOR;
493                         } else if(_menuPos == 2) {
494                                 _kln89->_drawApt = !_kln89->_drawApt;
495                         } else {
496                                 if(_kln89->_mapOrientation >= 2) {
497                                         // Don't allow heading up for now
498                                         _kln89->_mapOrientation = 0;
499                                 } else {
500                                         _kln89->_mapOrientation++;
501                                 }
502                                 _kln89->UpdateMapHeading();
503                         }
504                 } else if(_uLinePos == 3) {
505                         // TODO - add AUTO
506                         if(_kln89->_mapScaleIndex == 20) {
507                                 _kln89->_mapScaleIndex = 0;
508                         } else {
509                                 _kln89->_mapScaleIndex++;
510                         }
511                 }
512         }
513 }