From d176715284c9350413777342e24a76aecddd44ad Mon Sep 17 00:00:00 2001 From: daveluff Date: Wed, 30 Nov 2005 00:18:42 +0000 Subject: [PATCH] kln89 user interface logical pages --- src/Instrumentation/KLN89/kln89_page_act.cxx | 125 ++ src/Instrumentation/KLN89/kln89_page_act.hxx | 62 + src/Instrumentation/KLN89/kln89_page_apt.cxx | 854 ++++++++++++++ src/Instrumentation/KLN89/kln89_page_apt.hxx | 95 ++ src/Instrumentation/KLN89/kln89_page_cal.cxx | 110 ++ src/Instrumentation/KLN89/kln89_page_cal.hxx | 42 + src/Instrumentation/KLN89/kln89_page_dir.cxx | 103 ++ src/Instrumentation/KLN89/kln89_page_dir.hxx | 54 + src/Instrumentation/KLN89/kln89_page_fpl.cxx | 1029 +++++++++++++++++ src/Instrumentation/KLN89/kln89_page_fpl.hxx | 91 ++ src/Instrumentation/KLN89/kln89_page_int.cxx | 242 ++++ src/Instrumentation/KLN89/kln89_page_int.hxx | 56 + src/Instrumentation/KLN89/kln89_page_nav.cxx | 513 ++++++++ src/Instrumentation/KLN89/kln89_page_nav.hxx | 63 + src/Instrumentation/KLN89/kln89_page_ndb.cxx | 205 ++++ src/Instrumentation/KLN89/kln89_page_ndb.hxx | 52 + src/Instrumentation/KLN89/kln89_page_nrst.cxx | 86 ++ src/Instrumentation/KLN89/kln89_page_nrst.hxx | 48 + src/Instrumentation/KLN89/kln89_page_oth.cxx | 58 + src/Instrumentation/KLN89/kln89_page_oth.hxx | 39 + src/Instrumentation/KLN89/kln89_page_set.cxx | 291 +++++ src/Instrumentation/KLN89/kln89_page_set.hxx | 42 + src/Instrumentation/KLN89/kln89_page_usr.cxx | 51 + src/Instrumentation/KLN89/kln89_page_usr.hxx | 39 + src/Instrumentation/KLN89/kln89_page_vor.cxx | 217 ++++ src/Instrumentation/KLN89/kln89_page_vor.hxx | 52 + 26 files changed, 4619 insertions(+) create mode 100644 src/Instrumentation/KLN89/kln89_page_act.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_act.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_apt.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_apt.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_cal.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_cal.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_dir.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_dir.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_fpl.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_fpl.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_int.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_int.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_nav.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_nav.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_ndb.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_ndb.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_nrst.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_nrst.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_oth.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_oth.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_set.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_set.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_usr.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_usr.hxx create mode 100644 src/Instrumentation/KLN89/kln89_page_vor.cxx create mode 100644 src/Instrumentation/KLN89/kln89_page_vor.hxx diff --git a/src/Instrumentation/KLN89/kln89_page_act.cxx b/src/Instrumentation/KLN89/kln89_page_act.cxx new file mode 100644 index 000000000..d121820a6 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_act.cxx @@ -0,0 +1,125 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_act.hxx" +#include "kln89_page_apt.hxx" +#include "kln89_page_vor.hxx" +#include "kln89_page_ndb.hxx" +#include "kln89_page_int.hxx" +#include "kln89_page_usr.hxx" + +KLN89ActPage::KLN89ActPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 1; + _subPage = 0; + _name = "ACT"; + _actWp = NULL; + _actWpId = -1; + _actPage = NULL; + + _aptPage = new KLN89AptPage(parent); + _vorPage = new KLN89VorPage(parent); + _ndbPage = new KLN89NDBPage(parent); + _intPage = new KLN89IntPage(parent); + _usrPage = new KLN89UsrPage(parent); +} + +KLN89ActPage::~KLN89ActPage() { + delete _aptPage; + delete _vorPage; + delete _ndbPage; + delete _intPage; + delete _usrPage; +} + +void KLN89ActPage::Update(double dt) { + if(!_actWp) { + _actWp = _kln89->GetActiveWaypoint(); + _actWpId = _kln89->GetActiveWaypointIndex(); + } + if(_actWp) { + switch(_actWp->type) { + case GPS_WP_APT: _actPage = _aptPage; break; + case GPS_WP_VOR: _actPage = _vorPage; break; + case GPS_WP_NDB: _actPage = _ndbPage; break; + case GPS_WP_INT: _actPage = _intPage; break; + case GPS_WP_USR: _actPage = _usrPage; break; + default: + _actPage = NULL; + // ASSERT(0); // ie. we shouldn't ever get here. + } + } + + _id = _actWp->id; + if(_actPage) { + _actPage->SetId(_actWp->id); + _actPage->Update(dt); + } else { + KLN89Page::Update(dt); + } +} + +void KLN89ActPage::CrsrPressed() { + if(_actPage) { + _actPage->CrsrPressed(); + } else { + KLN89Page::CrsrPressed(); + } +} + +void KLN89ActPage::EntPressed() { + if(_actPage) { + _actPage->EntPressed(); + } else { + KLN89Page::EntPressed(); + } +} + +void KLN89ActPage::ClrPressed() { + if(_actPage) { + _actPage->ClrPressed(); + } else { + KLN89Page::ClrPressed(); + } +} + +void KLN89ActPage::Knob2Left1() { + if((_kln89->_mode != KLN89_MODE_CRSR) && (_actPage)) { + _actPage->Knob2Left1(); + } +} + +void KLN89ActPage::Knob2Right1() { + if((_kln89->_mode != KLN89_MODE_CRSR) && (_actPage)) { + _actPage->Knob2Right1(); + } +} + +void KLN89ActPage::LooseFocus() { + // Setting to NULL and -1 is better than resetting to + // active waypoint and index since we can't guarantee that + // the fpl active waypoint won't change behind our backs + // when we don't have focus. + _actWp = NULL; + _actWpId = -1; +} diff --git a/src/Instrumentation/KLN89/kln89_page_act.hxx b/src/Instrumentation/KLN89/kln89_page_act.hxx new file mode 100644 index 000000000..5e8d89c75 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_act.hxx @@ -0,0 +1,62 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_ACT_HXX +#define _KLN89_PAGE_ACT_HXX + +#include "kln89.hxx" + +class KLN89ActPage : public KLN89Page { + +public: + KLN89ActPage(KLN89* parent); + ~KLN89ActPage(); + + void Update(double dt); + + void CrsrPressed(); + void EntPressed(); + void ClrPressed(); + void Knob2Left1(); + void Knob2Right1(); + + void LooseFocus(); + +private: + // Position of the currently displayed waypoint within the active flightplan. + // -1 indicates no active flightplan. + int _actWpId; + + GPSWaypoint* _actWp; + + // The actual ACT page that gets displayed... + GPSPage* _actPage; + // ...which points to one of the below. + GPSPage* _aptPage; + GPSPage* _vorPage; + GPSPage* _ndbPage; + GPSPage* _intPage; + GPSPage* _usrPage; +}; + +#endif // _KLN89_PAGE_ACT_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx new file mode 100644 index 000000000..d1272e6cd --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -0,0 +1,854 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_apt.hxx" +#include + +// This function is copied from Airports/runways.cxx +// TODO - Make the original properly available and remove this instance!!!! +// Return reverse rwy number +// eg 01 -> 19 +// 03L -> 21R +static string GetReverseRunwayNo(string rwyno) { + // cout << "Original rwyno = " << rwyNo << '\n'; + + // standardize input number + string tmp = rwyno.substr(1, 1); + if (( tmp == "L" || tmp == "R" || tmp == "C" ) || (rwyno.size() == 1)) { + tmp = rwyno; + rwyno = "0" + tmp; + SG_LOG( SG_GENERAL, SG_INFO, + "Standardising rwy number from " << tmp << " to " << rwyno ); + } + + char buf[4]; + int rn = atoi(rwyno.substr(0,2).c_str()); + rn += 18; + while(rn > 36) { + rn -= 36; + } + sprintf(buf, "%02i", rn); + if(rwyno.size() == 3) { + if(rwyno.substr(2,1) == "L") { + buf[2] = 'R'; + buf[3] = '\0'; + } else if (rwyno.substr(2,1) == "R") { + buf[2] = 'L'; + buf[3] = '\0'; + } else if (rwyno.substr(2,1) == "C") { + buf[2] = 'C'; + buf[3] = '\0'; + } else if (rwyno.substr(2,1) == "T") { + buf[2] = 'T'; + buf[3] = '\0'; + } else { + SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code " + << rwyno << " passed to GetReverseRunwayNo(...)"); + } + } + return(buf); +} + +KLN89AptPage::KLN89AptPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 8; + _subPage = 0; + _name = "APT"; + _apt_id = "KHWD"; + // Make sure that _last_apt_id doesn't match at startup to force airport data to be fetched on first update. + _last_apt_id = "XXXX"; + _nRwyPages = 1; + _curRwyPage = 0; + _nFreqPages = 1; + _curFreqPage = 0; + ap = NULL; + _iapStart = 0; + _iafStart = 0; + _fStart = 0; + _iaps.clear(); + _iafDialog = false; + _addDialog = false; + _replaceDialog = false; + _curIap = 0; + _curIaf = 0; +} + +KLN89AptPage::~KLN89AptPage() { +} + +void KLN89AptPage::Update(double dt) { + bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false); + bool multi; // Not set by FindFirst... + bool exact = false; + if(_apt_id.size() == 4) exact = true; + // TODO - move this search out to where the button is pressed, and cache the result! + if(_apt_id != _last_apt_id || ap == NULL) ap = _kln89->FindFirstAptById(_apt_id, multi, exact); + //if(np == NULL) cout << "NULL... "; + //if(b == false) cout << "false...\n"; + /* + if(np && b) { + cout << "VOR FOUND!\n"; + } else { + cout << ":-(\n"; + } + */ + + if(ap) { + //cout << "Valid airport found! id = " << ap->getId() << ", elev = " << ap->getElevation() << '\n'; + if(_apt_id != _last_apt_id) { + UpdateAirport(ap->getId()); + _last_apt_id = _apt_id; + _curFreqPage = 0; + _curRwyPage = 0; + } + _apt_id = ap->getId(); + if(_kln89->GetActiveWaypoint()) { + if(_apt_id == _kln89->GetActiveWaypoint()->id) { + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + // Active waypoint arrow + _kln89->DrawSpecialChar(4, 2, 0, 3); + } + } + } + if(_kln89->_mode != KLN89_MODE_CRSR) { + if(!(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) { // Don't draw the airport name when the IAP dialogs are active + if(!_entInvert) { + if(!actPage) { + _kln89->DrawText(ap->getId(), 2, 1, 3); + } else { + // If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index. + _kln89->DrawText(ap->getId(), 2, 4, 3); + char buf[3]; + int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1); + _kln89->DrawText((string)buf, 2, 3 - n, 3); + } + } else { + if(!_kln89->_blink) { + _kln89->DrawText(ap->getId(), 2, 1, 3, false, 99); + _kln89->DrawEnt(); + } + } + } + } + if(_subPage == 0) { + // Name + _kln89->DrawText(ap->getName(), 2, 0, 2); + // Elevation + _kln89->DrawText(_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m", 2, 14, 3); + char buf[6]; + int n = snprintf(buf, 5, "%i", (_kln89->_altUnits == GPS_ALT_UNITS_FT ? (int)(ap->getElevation()) : (int)((double)ap->getElevation() * SG_FEET_TO_METER))); + _kln89->DrawText((string)buf, 2, 14 - n, 3); + // Town + airport_id_str_map_iterator itr = _kln89->_airportTowns.find(_apt_id); + if(itr != _kln89->_airportTowns.end()) { + _kln89->DrawText(itr->second, 2, 0, 1); + } + // State / Province / Country + itr = _kln89->_airportStates.find(_apt_id); + if(itr != _kln89->_airportStates.end()) { + _kln89->DrawText(itr->second, 2, 0, 0); + } + } else if(_subPage == 1) { + _kln89->DrawLatitude(ap->getLatitude(), 2, 3, 2); + _kln89->DrawLongitude(ap->getLongitude(), 2, 3, 1); + _kln89->DrawDirDistField(ap->getLatitude() * SG_DEGREES_TO_RADIANS, ap->getLongitude() * SG_DEGREES_TO_RADIANS, + 2, 0, 0, _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 5 ? true : false)); + } else if(_subPage == 2) { + // Try and calculate a realistic difference from UTC based on longitude + float degLonPerHr = 360.0 / 24.0; // 15 degrees per hour difference. + // Since 0 longitude is the middle of UTC, the boundaries will be at 7.5, 22.5, 37.5 etc. + int hrDiff = ((int)((fabs(ap->getLongitude())) + 7.5)) / 15; + _kln89->DrawText("UTC", 2, 0, 2); + if(hrDiff != 0) { + _kln89->DrawText(ap->getLongitude() >= 0.0 ? "+" : "-", 2, 3, 2); + char buf[3]; + snprintf(buf, 3, "%02i", hrDiff); + _kln89->DrawText((string)buf, 2, 4, 2); + _kln89->DrawText("( DT)", 2, 6, 2); + if(ap->getLongitude() >= 0.0) { + hrDiff++; + } else { + hrDiff--; + } + _kln89->DrawText(ap->getLongitude() >= 0.0 ? "+" : "-", 2, 7, 2); + snprintf(buf, 3, "%02i", hrDiff); + _kln89->DrawText((string)buf, 2, 8, 2); + } + // I guess we can make a heuristic guess as to fuel availability from the runway sizes + // For now assume that airports with asphalt or concrete runways will have at least 100L, + // and that runways over 4000ft will have JET. + if(_aptRwys[0]._surface_code <= 2) { + if(_aptRwys[0]._length >= 4000) { + _kln89->DrawText("JET 100L", 2, 0, 1); + } else { + _kln89->DrawText("100L", 2, 0, 1); + } + } + if(_iaps.empty()) { + _kln89->DrawText("NO APR", 2, 0, 0); + } else { + // TODO - output proper differentiation of ILS and NP APR and NP APR type eg GPS(R) + _kln89->DrawText("NP APR", 2, 0, 0); + } + } else if(_subPage == 3) { + if(_nRwyPages > 1) { + _kln89->DrawChar('+', 1, 3, 0); + } + unsigned int i = _curRwyPage * 2; + string s; + if(i < _aptRwys.size()) { + // Rwy No. + string s = _aptRwys[i]._rwy_no; + _kln89->DrawText(s, 2, 9, 3); + _kln89->DrawText("/", 2, 12, 3); + _kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 3); + // Length + s = GPSitoa(int(float(_aptRwys[i]._length) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5)); + _kln89->DrawText(s, 2, 5 - s.size(), 2); + _kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 2); + // Surface + // TODO - why not store these strings as an array? + switch(_aptRwys[i]._surface_code) { + case 1: + // Asphalt - fall through + case 2: + // Concrete + _kln89->DrawText("HRD", 2, 9, 2); + break; + case 3: + case 8: + // Turf / Turf helipad + _kln89->DrawText("TRF", 2, 9, 2); + break; + case 4: + case 9: + // Dirt / Dirt helipad + _kln89->DrawText("DRT", 2, 9, 2); + break; + case 5: + // Gravel + _kln89->DrawText("GRV", 2, 9, 2); + break; + case 6: + // Asphalt helipad - fall through + case 7: + // Concrete helipad + _kln89->DrawText("HRD", 2, 9, 2); + break; + case 12: + // Lakebed + _kln89->DrawText("CLY", 2, 9, 2); + default: + // erm? ... + _kln89->DrawText("MAT", 2, 9, 2); + } + } + i++; + if(i < _aptRwys.size()) { + // Rwy No. + string s = _aptRwys[i]._rwy_no; + _kln89->DrawText(s, 2, 9, 1); + _kln89->DrawText("/", 2, 12, 1); + _kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 1); + // Length + s = GPSitoa(int(float(_aptRwys[i]._length) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5)); + _kln89->DrawText(s, 2, 5 - s.size(), 0); + _kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 0); + // Surface + // TODO - why not store these strings as an array? + switch(_aptRwys[i]._surface_code) { + case 1: + // Asphalt - fall through + case 2: + // Concrete + _kln89->DrawText("HRD", 2, 9, 0); + break; + case 3: + case 8: + // Turf / Turf helipad + _kln89->DrawText("TRF", 2, 9, 0); + break; + case 4: + case 9: + // Dirt / Dirt helipad + _kln89->DrawText("DRT", 2, 9, 0); + break; + case 5: + // Gravel + _kln89->DrawText("GRV", 2, 9, 0); + break; + case 6: + // Asphalt helipad - fall through + case 7: + // Concrete helipad + _kln89->DrawText("HRD", 2, 9, 0); + break; + case 12: + // Lakebed + _kln89->DrawText("CLY", 2, 9, 0); + default: + // erm? ... + _kln89->DrawText("MAT", 2, 9, 0); + } + } + } else if(_subPage == 4) { + if(_nFreqPages > 1) { + _kln89->DrawChar('+', 1, 3, 0); + } + unsigned int i = _curFreqPage * 3; + if(i < _aptFreqs.size()) { + _kln89->DrawText(_aptFreqs[i].service, 2, 0, 2); + _kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 2); + } + i++; + if(i < _aptFreqs.size()) { + _kln89->DrawText(_aptFreqs[i].service, 2, 0, 1); + _kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 1); + } + i++; + if(i < _aptFreqs.size()) { + _kln89->DrawText(_aptFreqs[i].service, 2, 0, 0); + _kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 0); + } + } else if(_subPage == 5) { + // TODO - user ought to be allowed to leave persistent remarks + _kln89->DrawText("[Remarks]", 2, 2, 2); + } else if(_subPage == 6) { + // We don't have SID/STAR database yet + // TODO + _kln89->DrawText("No SID/STAR", 2, 3, 2); + _kln89->DrawText("In Data Base", 2, 2, 1); + _kln89->DrawText("For This Airport", 2, 0, 0); + } else if(_subPage == 7) { + if(_iaps.empty()) { + _kln89->DrawText("IAP", 2, 11, 3); + _kln89->DrawText("No Approach", 2, 3, 2); + _kln89->DrawText("In Data Base", 2, 2, 1); + _kln89->DrawText("For This Airport", 2, 0, 0); + } else { + if(_iafDialog) { + _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); + _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + _kln89->DrawText("IAF", 2, 2, 2); + int line = 0; + for(unsigned int i=_iafStart; i<_IAF.size(); ++i) { + if(line == 2) { + i = _IAF.size() - 1; + } + // Assume that the IAF number is always single digit! + _kln89->DrawText(GPSitoa(i+1), 2, 6, 2-line); + if(!(_kln89->_mode == KLN89_MODE_CRSR && _kln89->_blink && _uLinePos == (line + 1))) { + _kln89->DrawText(_IAF[i]->id, 2, 8, 2-line); + } + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (line + 1) && !(_kln89->_blink )) { + _kln89->Underline(2, 8, 2-line, 5); + } + ++line; + } + if(_uLinePos > 0 && !(_kln89->_blink)) { + _kln89->DrawEnt(); + } + } else if(_addDialog) { + _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); + _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + string s = GPSitoa(_fStart + 1); + _kln89->DrawText(s, 2, 2-s.size(), 2); + s = GPSitoa(_kln89->_approachFP->waypoints.size()); + _kln89->DrawText(s, 2, 2-s.size(), 1); + if(!(_uLinePos == _fStart+1 && _kln89->_blink)) { + _kln89->DrawText(_kln89->_approachFP->waypoints[_fStart]->id, 2, 4, 2); + if(_uLinePos == _fStart+1) _kln89->Underline(2, 4, 2, 6); + } + if(!(_uLinePos == _maxULinePos-1 && _kln89->_blink)) { + _kln89->DrawText(_kln89->_approachFP->waypoints[_kln89->_approachFP->waypoints.size()-1]->id, 2, 4, 1); + if(_uLinePos == _maxULinePos-1) _kln89->Underline(2, 4, 1, 6); + } + if(!(_uLinePos > _kln89->_approachFP->waypoints.size() && _kln89->_blink)) { + _kln89->DrawText("ADD TO FPL 0?", 2, 2, 0); + if(_uLinePos > _kln89->_approachFP->waypoints.size()) { + _kln89->Underline(2, 2, 0, 13); + _kln89->DrawEnt(); + } + } + } else if(_replaceDialog) { + _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); + _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + _kln89->DrawText("Replace Existing", 2, 0, 2); + _kln89->DrawText("Approach", 2, 4, 1); + if(_uLinePos > 0 && !(_kln89->_blink)) { + _kln89->DrawText("APPROVE?", 2, 4, 0); + _kln89->Underline(2, 4, 0, 8); + _kln89->DrawEnt(); + } + } else { + _kln89->DrawText("IAP", 2, 11, 3); + int check = 0; + bool selApp = false; + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos > 4) { + selApp = true; + if(!_kln89->_blink) _kln89->DrawEnt(); + } + for(unsigned int i=0; i<_iaps.size(); ++i) { // TODO - do this properly when > 3 IAPs + string s = GPSitoa(i+1); + _kln89->DrawText(s, 2, 2 - s.size(), 2-i); + if(!(selApp && _uLinePos == 5+i && _kln89->_blink)) { + _kln89->DrawText(_iaps[i]->_abbrev, 2, 3, 2-i); + _kln89->DrawText(_iaps[i]->_rwyStr, 2, 9, 2-i); + } + if(selApp && _uLinePos == 5+i && !_kln89->_blink) { + _kln89->Underline(2, 3, 2-i, 9); + } + check++; + if(check > 2) break; + } + } + } + } + } else { + if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_apt_id, 2, 1, 3); + if(_subPage == 0) { + /* + _kln89->DrawText("----.-", 2, 9, 3); + _kln89->DrawText("--------------", 2, 0, 2); + _kln89->DrawText("- -- --.--'", 2, 3, 1); + _kln89->DrawText("---- --.--'", 2, 3, 0); + _kln89->DrawSpecialChar(0, 2, 7, 1); + _kln89->DrawSpecialChar(0, 2, 7, 0); + */ + } + } + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(!(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) { + if(_uLinePos > 0 && _uLinePos < 5) { + // TODO - blink as well + _kln89->Underline(2, _uLinePos, 3, 1); + } + for(unsigned int i = 0; i < _apt_id.size(); ++i) { + if(_uLinePos != (i + 1)) { + _kln89->DrawChar(_apt_id[i], 2, i + 1, 3); + } else { + if(!_kln89->_blink) _kln89->DrawChar(_apt_id[i], 2, i + 1, 3); + } + } + } + } + + _id = _apt_id; + + KLN89Page::Update(dt); +} + +void KLN89AptPage::SetId(string s) { + _last_apt_id = _apt_id; + _save_apt_id = _apt_id; + _apt_id = s; + UpdateAirport(s); // If we don't do this here we break things if s is the same as the current ID since the update wouldn't get called then. +} + +// Update the cached airport details +void KLN89AptPage::UpdateAirport(const string& id) { + // Frequencies + _aptFreqs.clear(); + ATCData ad; + AptFreq aq; + //cout << "UpdateAirport called, id = " << id << '\n'; + // TODO - the logic below only returns one service per type per airport - they can be on more than one freq though. + if(current_commlist->FindByCode(id, ad, ATIS)) { + //cout << "Found ATIS\n"; + aq.service = "ATIS*"; + aq.freq = ad.freq; + _aptFreqs.push_back(aq); + } + if(current_commlist->FindByCode(id, ad, GROUND)) { + aq.service = "GRND*"; + aq.freq = ad.freq; + _aptFreqs.push_back(aq); + } + if(current_commlist->FindByCode(id, ad, TOWER)) { + aq.service = "TWR *"; + aq.freq = ad.freq; + _aptFreqs.push_back(aq); + } + if(current_commlist->FindByCode(id, ad, APPROACH)) { + aq.service = "APR"; + aq.freq = ad.freq; + _aptFreqs.push_back(aq); + } + _nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f); + + // Runways + _aptRwys.clear(); + FGRunway r; + bool haveRwy = globals->get_runways()->search(id, &r); + while(haveRwy && r._id == id) { + // Insert the runway with longest at the start of the array + for(unsigned int i = 0; i <= _aptRwys.size(); ++i) { + if(i == _aptRwys.size()) { + _aptRwys.push_back(r); + break; + } else { + if(r._length > _aptRwys[i]._length) { + _aptRwys.insert(_aptRwys.begin() + i, r); + break; + } + } + } + haveRwy = globals->get_runways()->next(&r); + } + _nRwyPages = (_aptRwys.size() + 1) / 2; // 2 runways per page. + if(_nFreqPages < 1) _nFreqPages = 1; + if(_nRwyPages < 1) _nRwyPages = 1; + + // Instrument approaches + // Only non-precision for now - TODO - handle precision approaches if necessary + _iaps.clear(); + iap_map_iterator itr = _kln89->_np_iap.find(id); + if(itr != _kln89->_np_iap.end()) { + _iaps = itr->second; + } + if(_subPage == 7) _maxULinePos = 4 + _iaps.size(); // We shouldn't need to check the crsr for out-of-bounds here since we only update the airport details when the airport code is changed - ie. _uLinePos <= 4! +} + +void KLN89AptPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) { + if(_subPage == 7) { + // Pressing crsr jumps back to vanilla IAP page. + _iafDialog = false; + _addDialog = false; + _replaceDialog = false; + } + return; + } + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + _uLinePos = 1; + } + if(_subPage == 0) { + _maxULinePos = 32; + } else if(_subPage == 7) { + // Don't *think* we need some of this since some of it we can only get to by pressing ENT, not CRSR. + if(_iafDialog) { + _maxULinePos = _IAF.size(); + _uLinePos = 1; + } else if(_addDialog) { + _maxULinePos = 1; + _uLinePos = 1; + } else if(_replaceDialog) { + _maxULinePos = 1; + _uLinePos = 1; + } else { + _maxULinePos = 4 + _iaps.size(); + if(_iaps.empty()) { + _uLinePos = 1; + } else { + _uLinePos = 5; + } + } + } else { + _maxULinePos = 5; + } +} + +void KLN89AptPage::ClrPressed() { + if(_subPage == 1 && _uLinePos == 5) { + _to_flag = !_to_flag; + } else if(_subPage == 7) { + // Clear backs out IAP selection one step at a time + if(_iafDialog) { + _iafDialog = false; + _maxULinePos = 4 + _iaps.size(); + if(_iaps.empty()) { + _uLinePos = 1; + } else { + _uLinePos = 5; + } + } else if(_addDialog) { + _addDialog = false; + if(_IAF.size() > 1) { + _iafDialog = true; + _maxULinePos = 1; + // Don't reset _curIaf since it is remembed. + _uLinePos = 1 + _curIaf; // TODO - make this robust to more than 3 IAF + } else { + _maxULinePos = 4 + _iaps.size(); + if(_iaps.empty()) { + _uLinePos = 1; + } else { + _uLinePos = 5; + } + } + } else if(_replaceDialog) { + _replaceDialog = false; + _addDialog = true; + _maxULinePos = 1; + _uLinePos = 1; + } + } +} + +void KLN89AptPage::EntPressed() { + //cout << "A\n" + if(_entInvert) { + _entInvert = false; + _last_apt_id = _apt_id; + _apt_id = _save_apt_id; + } else if(_subPage == 7 && _kln89->_mode == KLN89_MODE_CRSR && _uLinePos > 0) { + //cout << "B\n"; + // We are selecting an approach + if(_iafDialog) { + //cout << "C\n"; + if(_uLinePos > 0) { + // Record the IAF that was picked + if(_uLinePos == 3) { + _curIaf = _IAF.size() - 1; + } else { + _curIaf = _uLinePos - 1 + _iafStart; + } + //cout << "_curIaf = " << _curIaf << '\n'; + // TODO - delete the waypoints inside _approachFP before clearing them!!!!!!! + _kln89->_approachFP->waypoints.clear(); + GPSWaypoint* wp = new GPSWaypoint; + *wp = *_IAF[_curIaf]; // Need to make copies here since we're going to alter ID and type sometimes + string iafid = wp->id; + //wp->id += 'i'; + _kln89->_approachFP->waypoints.push_back(wp); + for(unsigned int i=0; i<_IAP.size(); ++i) { + if(_IAP[i]->id != iafid) { // Don't duplicate waypoints that are part of the initial fix list and the approach procedure list. + // FIXME - allow the same waypoint to be both the IAF and the FAF in some + // approaches that have a procedure turn eg. KDLL + // Also allow MAF to be the same as IAF! + wp = new GPSWaypoint; + *wp = *_IAP[i]; + //cout << "Adding waypoint " << wp->id << ", type is " << wp->appType << '\n'; + //if(wp->appType == GPS_FAF) wp->id += 'f'; + //if(wp->appType == GPS_MAP) wp->id += 'm'; + //cout << "New id = " << wp->id << '\n'; + _kln89->_approachFP->waypoints.push_back(wp); + } + } + // Only add 1 missed approach procedure waypoint for now. I think this might be standard always anyway. + wp = new GPSWaypoint; + *wp = *_MAP[0]; + //wp->id += 'h'; + _kln89->_approachFP->waypoints.push_back(wp); + _iafDialog = false; + _addDialog = true; + _maxULinePos = _kln89->_approachFP->waypoints.size() + 1; + _uLinePos = _maxULinePos; + } + } else if(_addDialog) { + if(_uLinePos == _maxULinePos) { + _addDialog = false; + if(_kln89->ApproachLoaded()) { + _replaceDialog = true; + _uLinePos = 1; + _maxULinePos = 1; + } else { + // Now load the approach into the active flightplan. + // As far as I can tell, the rules are this: + // If the airport of the approach is in the flightplan, insert it prior to this. (Not sure what happens if airport has already been passed). + // If the airport is not in the flightplan, append the approach to the flightplan, even if it is closer than the current active leg, + // in which case reorientate to flightplan might put us on the approach, but unable to activate it. + // However, it appears from the sim as if this can indeed happen if the user is not carefull. + bool added = false; + for(unsigned int i=0; i<_kln89->_activeFP->waypoints.size(); ++i) { + if(_kln89->_activeFP->waypoints[i]->id == _apt_id) { + _kln89->_activeFP->waypoints.insert(_kln89->_activeFP->waypoints.begin()+i, _kln89->_approachFP->waypoints.begin(), _kln89->_approachFP->waypoints.end()); + added = true; + break; + } + } + if(!added) { + _kln89->_activeFP->waypoints.insert(_kln89->_activeFP->waypoints.end(), _kln89->_approachFP->waypoints.begin(), _kln89->_approachFP->waypoints.end()); + } + _kln89->_approachID = _apt_id; + _kln89->_approachAbbrev = _iaps[_curIap]->_abbrev; + _kln89->_approachRwyStr = _iaps[_curIap]->_rwyStr; + _kln89->_approachLoaded = true; + //_kln89->_messageStack.push_back("*Press ALT To Set Baro"); + // Actually - this message is only sent when we go into appraoch-arm mode. + // TODO - check the flightplan for consistency + _kln89->OrientateToActiveFlightPlan(); + _kln89->_mode = KLN89_MODE_DISP; + _kln89->_curPage = 7; + _kln89->_activePage = _kln89->_pages[7]; // Do we need to clean up here at all before jumping? + } + } + } else if(_replaceDialog) { + // TODO - load the approach! + } else if(_uLinePos > 4) { + _IAF.clear(); + _IAP.clear(); + _MAP.clear(); + _curIaf = 0; + _IAF = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_IAF; + _IAP = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_IAP; + _MAP = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_MAP; + _curIap = _uLinePos - 5; // TODO - handle the start of list ! no. 1, and the end of list not sequential! + _uLinePos = 1; + if(_IAF.size() > 1) { + // More than 1 IAF - display the selection dialog + _iafDialog = true; + _maxULinePos = _IAF.size(); + } else { + _addDialog = true; + _maxULinePos = 1; + } + } + } +} + +void KLN89AptPage::Knob1Left1() { + if(_kln89->_mode == KLN89_MODE_CRSR && _subPage == 7 && _addDialog) { + if(_uLinePos == _maxULinePos) { + _uLinePos--; + if(_kln89->_approachFP->waypoints.size() > 1) _fStart = _kln89->_approachFP->waypoints.size() - 2; + } else if(_uLinePos == _maxULinePos - 1) { + _uLinePos--; + } else if(_uLinePos > 0) { + if(_fStart == 0) { + _uLinePos--; + } else { + _uLinePos--; + _fStart--; + } + } + } else { + KLN89Page::Knob1Left1(); + } +} + +void KLN89AptPage::Knob1Right1() { + if(_kln89->_mode == KLN89_MODE_CRSR && _subPage == 7 && _addDialog) { + if(_uLinePos == _maxULinePos) { + // no-op + } else if(_uLinePos == _maxULinePos - 1) { + _uLinePos++; + _fStart = 0; + } else if(_uLinePos > 0) { + if(_fStart >= _kln89->_approachFP->waypoints.size() - 2) { + _uLinePos++; + } else { + _uLinePos++; + _fStart++; + } + } else if(_uLinePos == 0) { + _uLinePos++; + _fStart = 0; + } + } else { + KLN89Page::Knob1Right1(); + } +} + +void KLN89AptPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + if(_uLinePos == 0 && _kln89->_mode == KLN89_MODE_CRSR && _kln89->_obsMode) { + KLN89Page::Knob2Left1(); + } else if(_subPage == 5) { + _subPage = 4; + _curFreqPage = _nFreqPages - 1; + } else if(_subPage == 4) { + // Freqency pages + if(_curFreqPage == 0) { + _subPage = 3; + _curRwyPage = _nRwyPages - 1; + } else { + _curFreqPage--; + } + } else if(_subPage == 3) { + if(_curRwyPage == 0) { + KLN89Page::Knob2Left1(); + } else { + _curRwyPage--; + } + } else { + KLN89Page::Knob2Left1(); + } + } else { + if(_uLinePos < 5 && !(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) { + // Same logic for all pages - set the ID + _apt_id = _apt_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_apt_id.size() + 1)) { + _apt_id += '9'; + } else { + _apt_id[_uLinePos - 1] = _kln89->DecChar(_apt_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // TODO - set by name + } else { + // NO-OP - to/fr is cycled by clr button + } + } + } +} + +void KLN89AptPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + if(_uLinePos == 0 && _kln89->_mode == KLN89_MODE_CRSR && _kln89->_obsMode) { + KLN89Page::Knob2Right1(); + } else if(_subPage == 2) { + _subPage = 3; + _curRwyPage = 0; + } else if(_subPage == 3) { + if(_curRwyPage == _nRwyPages - 1) { + _subPage = 4; + _curFreqPage = 0; + } else { + _curRwyPage++; + } + } else if(_subPage == 4) { + if(_curFreqPage == _nFreqPages - 1) { + _subPage = 5; + } else { + _curFreqPage++; + } + } else { + KLN89Page::Knob2Right1(); + } + } else { + if(_uLinePos < 5 && !(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) { + // Same logic for all pages - set the ID + _apt_id = _apt_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_apt_id.size() + 1)) { + _apt_id += 'A'; + } else { + _apt_id[_uLinePos - 1] = _kln89->IncChar(_apt_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // TODO - set by name + } else { + // NO-OP - to/fr is cycled by clr button + } + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_apt.hxx b/src/Instrumentation/KLN89/kln89_page_apt.hxx new file mode 100644 index 000000000..d5814fda8 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_apt.hxx @@ -0,0 +1,95 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_APT +#define _KLN89_PAGE_APT + +#include "kln89.hxx" + +#include + +struct AptFreq { + string service; + unsigned short int freq; +}; + +class KLN89AptPage : public KLN89Page { + +public: + KLN89AptPage(KLN89* parent); + ~KLN89AptPage(); + + void Update(double dt); + + void CrsrPressed(); + void ClrPressed(); + void EntPressed(); + void Knob1Left1(); + void Knob1Right1(); + void Knob2Left1(); + void Knob2Right1(); + + void SetId(string s); + +private: + // Update the cached airport details + void UpdateAirport(const string& id); + + string _apt_id; + string _last_apt_id; + string _save_apt_id; + const FGAirport* ap; + + vector _aptRwys; + vector _aptFreqs; + + iap_list_type _iaps; + unsigned int _curIap; // The index into _iaps of the IAP we are currently selecting + vector _IAF; // The initial approach fix(es) + vector _IAP; // The compulsory waypoints of the approach procedure (may duplicate one of the above). + // _IAP includes the FAF and MAF. + vector _MAP; // The missed approach procedure (doesn't include the MAF). + unsigned int _curIaf; // The index into _IAF of the IAF we are currently selecting, and then remembered as the one we selected + + // Position in rwy pages + unsigned int _curRwyPage; + unsigned int _nRwyPages; + + // Position in freq pages + unsigned int _curFreqPage; + unsigned int _nFreqPages; + + // Position in IAP list (0-based number of first IAP displayed) + unsigned int _iapStart; + // ditto for IAF list (can't test this since can't find an approach with > 3 IAF at the moment!) + unsigned int _iafStart; + // ditto for list of approach fixes when asking load confirmation + unsigned int _fStart; + + // Various IAP related dialog states that we might need to remember + bool _iafDialog; + bool _addDialog; + bool _replaceDialog; +}; + +#endif // _KLN89_PAGE_APT diff --git a/src/Instrumentation/KLN89/kln89_page_cal.cxx b/src/Instrumentation/KLN89/kln89_page_cal.cxx new file mode 100644 index 000000000..42b9f3ea3 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_cal.cxx @@ -0,0 +1,110 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_cal.hxx" + +KLN89CalPage::KLN89CalPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 8; + _subPage = 0; + _name = "CAL"; + _nFp0 = 0; + _ground_speed_ms = 110 * 0.514444444444; +} + +KLN89CalPage::~KLN89CalPage() { +} + +void KLN89CalPage::Update(double dt) { + if(_subPage == 0) { + if(1) { // TODO - fix this hardwiring! + // Flightplan calc + _kln89->DrawText(">Fpl:", 2, 0, 3); + _kln89->DrawText("0", 2, 6, 3);// TODO - fix this hardwiring! + GPSFlightPlan* fp = _kln89->_flightPlans[_nFp0]; + if(fp) { + unsigned int n = fp->waypoints.size(); + if(n < 2) { + // TODO - check that this is what really happens + _kln89->DrawText("----", 2, 9, 3); + _kln89->DrawText("----", 2, 9, 2); + } else { + _kln89->DrawText(fp->waypoints[0]->id, 2, 9, 3); + _kln89->DrawText(fp->waypoints[n-1]->id, 2, 9, 2); + double cum_tot_m = 0.0; + for(unsigned int i = 1; i < fp->waypoints.size(); ++i) { + cum_tot_m += _kln89->GetGreatCircleDistance(fp->waypoints[i-1]->lat, fp->waypoints[i-1]->lon, + fp->waypoints[i]->lat, fp->waypoints[i]->lon); + } + double ete = (cum_tot_m * SG_NM_TO_METER) / _ground_speed_ms; + _kln89->DrawDist(cum_tot_m, 2, 5, 1); + _kln89->DrawSpeed(_ground_speed_ms / 0.5144444444, 2, 5, 0); + _kln89->DrawTime(ete, 2, 14, 0); + } + } else { + _kln89->DrawText("----", 2, 9, 3); + _kln89->DrawText("----", 2, 9, 2); + } + } else { + _kln89->DrawText(">Wpt:", 2, 0, 3); + } + _kln89->DrawText("To", 2, 6, 2); + _kln89->DrawText("ESA ----'", 2, 7, 1); // TODO - implement an ESA calc + _kln89->DrawText("ETE", 2, 7, 0); + } else if(_subPage == 1) { + _kln89->DrawText(">Fpl: 0", 2, 0, 3); // TODO - fix this hardwiring! + _kln89->DrawText("FF:", 2, 0, 2); + _kln89->DrawText("Res:", 2, 7, 1); + _kln89->DrawText("Fuel Req", 2, 0, 0); + } else if(_subPage == 2) { + _kln89->DrawText("Time:", 2, 0, 3); + _kln89->DrawText("Alarm at:", 2, 0, 2); + _kln89->DrawText("in:", 2, 6, 1); + _kln89->DrawText("Elapsed", 2, 0, 0); + } else if(_subPage == 3) { + _kln89->DrawText("PRESSURE ALT", 2, 1, 3); + _kln89->DrawText("Ind:", 2, 0, 2); + _kln89->DrawText("Baro:", 2, 0, 1); + _kln89->DrawText("Prs", 2, 0, 0); + } else if(_subPage == 4) { + _kln89->DrawText("DENSITY ALT", 2, 1, 3); + _kln89->DrawText("Prs:", 2, 0, 2); + _kln89->DrawText("Temp:", 2, 0, 1); + _kln89->DrawText("Den", 2, 0, 0); + } else if(_subPage == 5) { + _kln89->DrawText("CAS:", 2, 0, 3); + _kln89->DrawText("Prs:", 2, 0, 2); + _kln89->DrawText("Temp:", 2, 0, 1); + _kln89->DrawText("TAS", 2, 0, 0); + } else if(_subPage == 6) { + _kln89->DrawText("TAS:", 2, 0, 3); + _kln89->DrawText("Hdg:", 2, 0, 2); + _kln89->DrawText("Headwind:", 2, 0, 1); + _kln89->DrawText("True", 2, 4, 0); + } else { + _kln89->DrawText("SUNRISE", 2, 0, 1); + _kln89->DrawText("SUNSET", 2, 0, 0); + } + + KLN89Page::Update(dt); +} diff --git a/src/Instrumentation/KLN89/kln89_page_cal.hxx b/src/Instrumentation/KLN89/kln89_page_cal.hxx new file mode 100644 index 000000000..c8e832fb2 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_cal.hxx @@ -0,0 +1,42 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_CAL +#define _KLN89_PAGE_CAL + +#include "kln89.hxx" + +class KLN89CalPage : public KLN89Page { + +public: + KLN89CalPage(KLN89* parent); + ~KLN89CalPage(); + + void Update(double dt); + +private: + unsigned int _nFp0; // flightplan no. displayed on page 1 (_subPage == 0). + double _ground_speed_ms; // Assumed ground speed for ete calc on page 1 (user can alter this). +}; + +#endif // _KLN89_PAGE_CAL diff --git a/src/Instrumentation/KLN89/kln89_page_dir.cxx b/src/Instrumentation/KLN89/kln89_page_dir.cxx new file mode 100644 index 000000000..63c75abe8 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_dir.cxx @@ -0,0 +1,103 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_dir.hxx" + +KLN89DirPage::KLN89DirPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 1; + _subPage = 0; + _name = "DIR"; + _DToWpDispMode = 2; +} + +KLN89DirPage::~KLN89DirPage() { +} + +void KLN89DirPage::Update(double dt) { + // TODO - this can apparently be "ACTIVATE:" under some circumstances + _kln89->DrawText("DIRECT TO:", 2, 2, 3); + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_DToWpDispMode == 0) { + string s = _id; + while(s.size() < 5) s += ' '; + if(!_kln89->_blink) { + _kln89->DrawText(s, 2, 4, 1, false, 99); + _kln89->DrawEnt(1, 0, 1); + } + } else if(_DToWpDispMode == 1) { + if(!_kln89->_blink) { + // TODO + _kln89->DrawEnt(1, 0, 1); + } + _kln89->Underline(2, 4, 1, 5); + } else { + if(!_kln89->_blink) _kln89->DrawText("_____", 2, 4, 1); + _kln89->Underline(2, 4, 1, 5); + } + } else { + _kln89->DrawText("_____", 2, 4, 1); + } + + KLN89Page::Update(dt); +} + +void KLN89DirPage::SetId(string s) { + if(s.size()) { + _id = s; + // TODO - fill in lat, lon, type + // or just pass in waypoints (probably better!) + _DToWpDispMode = 0; + // TODO - this (above) should probably be dependent on whether s is a *valid* waypoint! + } else { + _DToWpDispMode = 2; + } + _saveMasterMode = _kln89->_mode; + _uLinePos = 1; // Needed to stop Leg flashing +} + +void KLN89DirPage::ClrPressed() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_DToWpDispMode <= 1) { + _DToWpDispMode = 2; + _id.clear(); + } else { + // Restore the original master mode + _kln89->_mode = _saveMasterMode; + // Stop displaying dir page + _kln89->_activePage = _kln89->_pages[_kln89->_curPage]; + } + } else { + // TODO + } +} + +void KLN89DirPage::EntPressed() { + //cout << "DTO ENT Pressed()\n"; + if(_id.empty()) { + _kln89->DtoCancel(); + } else { + _kln89->DtoInitiate(_id); + } +} \ No newline at end of file diff --git a/src/Instrumentation/KLN89/kln89_page_dir.hxx b/src/Instrumentation/KLN89/kln89_page_dir.hxx new file mode 100644 index 000000000..ec31df4aa --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_dir.hxx @@ -0,0 +1,54 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_DIR +#define _KLN89_PAGE_DIR + +#include "kln89.hxx" + +class KLN89DirPage : public KLN89Page { + +public: + KLN89DirPage(KLN89* parent); + ~KLN89DirPage(); + + void Update(double dt); + + void SetId(string s); + + void ClrPressed(); + void EntPressed(); + +private: + // Waypoint display mode. + // There are a number of ways that the waypoint can be displayed in the DIR page: + // 0 => Whole candidate waypoint displayed, entirely inverted. This is normally how the page is initially displayed, unless a candidate waypoint cannot be determined. + // 1 => Waypoint being entered, with a corresponding cursor position, and only the cursor position inverted. + // 2 => Blanks. These can be displayed flashing when the cursor is active (eg. when CLR is pressed) and are always displayed if the cursor is turned off. + int _DToWpDispMode; + + // We need to save the mode when DTO gets pressed, since potentially this class handles page exit via. the CLR event handler + KLN89Mode _saveMasterMode; +}; + +#endif // _KLN89_PAGE_DIR diff --git a/src/Instrumentation/KLN89/kln89_page_fpl.cxx b/src/Instrumentation/KLN89/kln89_page_fpl.cxx new file mode 100644 index 000000000..99dfe982a --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_fpl.cxx @@ -0,0 +1,1029 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_fpl.hxx" +#include + +using namespace std; + +KLN89FplPage::KLN89FplPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 26; + _subPage = 0; + _name = "FPL"; + _fpMode = 0; + _actFpMode = 0; + _wLinePos = 0; + _bEntWp = false; + _bEntExp = false; + _entWp = NULL; + _fplPos = 0; + _resetFplPos0 = true; + _delFP = false; + _delWp = false; + _delAppr = false; + _changeAppr = false; + _fp0SelWpId = ""; +} + +KLN89FplPage::~KLN89FplPage() { +} + +void KLN89FplPage::Update(double dt) { + Calc(); + + // NOTE - we need to draw the active leg arrow outside of this block to avoid the _delFP check. + // TODO - we really ought to merge the page 0 and other pages drawing code with a couple of lines of extra logic. + if(_subPage == 0 && !_delFP) { // Note that in the _delFP case, the active flightplan gets a header, and hence the same geometry as the other fps, so we draw it there. + // active FlightPlan + // NOTE THAT FOR THE ACTIVE FLIGHT PLAN, TOP POSITION IS STILL 4 in the underline position scheme, to make + // copy and paste easier!!!! + + // ---------------------------------- Copy the active FlightPlan and insert approach header and fence if required --------------- + // For synatical convienience + //vector waylist = _kln89->_flightPlans[_subPage]->waypoints; + // Copy every waypoint for now. + // This is inefficient, but allows us to insert dummy waypoints to represent the header and fence + // in our *local copy* of the flightplan, if an approach is loaded. There must be a better way to do this!!!! + //cout << "AA" << endl; + vector waylist; + for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { + waylist.push_back(*_kln89->_flightPlans[_subPage]->waypoints[i]); + } + //cout << "BB" << endl; + _hdrPos = -1; + _fencePos = -1; + if(_kln89->_approachLoaded) { + GPSWaypoint wp; + wp.id = "HHHH"; + wp.type = GPS_WP_VIRT; + wp.appType = GPS_HDR; + //cout << "CC" << endl; + for(unsigned int i=0; i numlist; + numlist.clear(); + for(unsigned int i=0; iGetActiveWaypointIndex(); + if(_resetFplPos0) { + if(waylist.size() <= 1) { + _fplPos = 0; + } else if(waylist.size() <= 4) { + _fplPos = 1; + } else { + // Make the active waypoint the second WP displayed + _fplPos = idx; + if(_fplPos != 0) { + _fplPos--; + } + } + //cout << "HeaderPos = " << _hdrPos << ", fencePos = " << _fencePos << ", _fplPos = " << _fplPos << ", active waypoint index = " << _parent->GetActiveWaypointIndex() << '\n'; + if(_hdrPos >= 0 && idx >= _hdrPos) { + _fplPos++; + if(_fencePos >= 0 && (idx + 1) >= _fencePos) { + _fplPos++; + } + } + _resetFplPos0 = false; + } + + // Increment the active waypoint position if required due hdr and fence here not above so it gets called every frame + if(_hdrPos >= 0 && idx >= _hdrPos) { + idx++; + if(_fencePos >= 0 && idx >= _fencePos) { + idx++; + } + } + + // Draw the leg arrow etc + int diff = idx - (int)_fplPos; + int drawPos = -1; + if(idx < 0) { + // No active waypoint + } else if(diff < 0) { + // Off screen to the top + } else if(diff > 2) { + // TODO ! + } else { + drawPos = diff; + } + // Only the head is blinked during waypoint alerting + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + _kln89->DrawSpecialChar(4, 2, 0, 3-drawPos); + } + // If the active waypoint is immediately after an approach header then we need to do an extra-long tail leg + if(_hdrPos >= 0 && idx == _hdrPos + 1) { + if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLongLegTail(3-drawPos); + } else { + if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLegTail(3-drawPos); + } + + //cout << "Top pos is " << _fplPos0 << ' '; + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_uLinePos == 3) { + _kln89->Underline(2, 13, 3, 3); + } else if(_uLinePos >= 4) { + if(_bEntWp) { + if(_wLinePos == 0) { + _kln89->Underline(2, 5, 3 - (_uLinePos - 4), 4); + } else if(_wLinePos == 4) { + _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 4); + } else { + _kln89->Underline(2, 4, 3 - (_uLinePos - 4), _wLinePos); + _kln89->Underline(2, 5 + _wLinePos, 3 - (_uLinePos - 4), 4 - _wLinePos); + } + if(!_kln89->_blink) { + //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos); + _kln89->DrawEnt(); + } + } else { + _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 5); + } + } + } + // ---------------------------------- + //cout << "A1" << endl; + + // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off + if((int)_fplPos > ((int)waylist.size()) - 3) _fplPos = (((int)waylist.size()) - 3 < 0 ? 0 : waylist.size() - 3); + unsigned int last_pos; + if(waylist.empty()) { + last_pos = 0; + } else { + last_pos = ((int)_fplPos == ((int)waylist.size()) - 3 ? waylist.size() : waylist.size() - 1); + } + //cout << "Initialising last_pos, last_pos = " << last_pos << '\n'; + //cout << "B1" << endl; + if(waylist.size() < 4) last_pos = waylist.size(); + + // Don't draw the cyclic field header if the top waypoint is the approach header + // Not sure if this also applies to the fence - don't think so but TODO - check! + if(waylist[_fplPos].appType != GPS_HDR) { + _kln89->DrawChar('>', 2, 12, 3); + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) { + DrawFpMode(3); + } + } + + // ACTIVE + for(unsigned int i=0; i<4; ++i) { + //cout << "F1... " << i << endl; + // Don't draw the waypoint number for the header or fence + //cout << "_fplPos0 = " << _fplPos0 << ", waylist size is " << waylist.size() << '\n'; + //cout << "F1, i = " << i << ", way id = " << waylist[_fplPos0+i].id << '\n'; + if((waylist[_fplPos+i].appType == GPS_HDR || waylist[_fplPos+i].appType == GPS_FENCE) + && i != 3) { // By definition, the header and fence lines can't be displayed on the last line hence the unconditional !i==3 is safe. + // no-op + //cout << "NOOP\n"; + } else { + int n = (i < 3 ? _fplPos + i + 1 : last_pos + 1); + if(_kln89->_approachLoaded) { + if(n > _hdrPos) --n; + if(n > _fencePos) --n; + } + string s = GPSitoa(n); + // Don't draw the colon for waypoints that are part of the published approach + if(waylist[_fplPos+i].appType == GPS_APP_NONE) { + s += ':'; + } + if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - (s[s.size()-1] == ':' ? s.size() : s.size()+1), 3 - i); + } + //cout << "F1 done!\n"; + bool drawID = true; + if(_delWp && _uLinePos == i+4) { + if(!_kln89->_blink) { + _kln89->DrawText("Del", 2, 0, 3-i); + _kln89->DrawChar('?', 2, 10, 3-i); + _kln89->Underline(2, 0, 3-i, 11); + _kln89->DrawEnt(); + } + } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) { + if(!_kln89->_blink) { + if(_wLinePos >= _entWp->id.size()) { + _kln89->DrawText(_entWp->id, 2, 4, 3-i); + _kln89->DrawChar(' ', 2, 4+_wLinePos, 3-i, false, true); + } else { + _kln89->DrawText(_entWp->id.substr(0, _wLinePos), 2, 4, 3-i); + _kln89->DrawChar(_entWp->id[_wLinePos], 2, 4+_wLinePos, 3-i, false, true); + _kln89->DrawText(_entWp->id.substr(_wLinePos+1, _entWp->id.size()-_wLinePos-1), 2, 5+_wLinePos, 3-i); + } + } + drawID = false; + } + //cout << "F2" << endl; + if(drawID) { + //cout << "F2a" << endl; + if(i == 3 || _fplPos + i == waylist.size()) { + //cout << "F2a1" << endl; + //cout << "_uLinePos = " << _uLinePos << ", i = " << i << ", waylist.size() = " << waylist.size() << endl; + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) { + //cout << "Drawing underline..." << endl; + _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos].GetAprId() : "_____", 2, 4, 3-i); + //cout << "2" << endl; + } + //cout << "3" << endl; + //cout << "last_pos = " << last_pos << endl; + if(last_pos > 0 && last_pos < waylist.size() && i > 0) { + //cout << "4" << endl; + // Draw the param + if(_actFpMode == 0) { + string s = _params[last_pos - 1]; + _kln89->DrawText(s, 2, 16-s.size(), 3-i); + } else if(_actFpMode == 3) { + string s = _params[last_pos - 1]; + _kln89->DrawText(s, 2, 15-s.size(), 3-i); + _kln89->DrawSpecialChar(0, 2, 15, 3-i); + } + //cout << "5" << endl; + } + //cout << "6" << endl; + break; + } else { + //cout << "F2a2" << endl; + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) { + if(waylist[_fplPos+i].appType == GPS_HDR) { + if(_delAppr) { + _kln89->DrawText("DELETE APPR?", 2, 1, 3-i); + } else if(_changeAppr) { + _kln89->DrawText("CHANGE APPR?", 2, 1, 3-i); + } else { + _kln89->DrawText(_kln89->_approachAbbrev, 2, 1, 3-i); + _kln89->DrawText(_kln89->_approachRwyStr, 2, 7, 3-i); + _kln89->DrawText(_kln89->_approachID, 2, 12, 3-i); + } + } else if(waylist[_fplPos+i].appType == GPS_FENCE) { + _kln89->DrawText("*NO WPT SEQ", 2, 0, 3-i); + } else { + _kln89->DrawText(waylist[_fplPos+i].GetAprId(), 2, 4, 3-i); + } + } + } + //cout << "F2b" << endl; + if(i > 0) { + // Draw the param + //cout << "i > 0 param draw...\n"; + if(_actFpMode == 0) { + string s = _params[_fplPos + i - 1]; + _kln89->DrawText(s, 2, 16-s.size(), 3-i); + } else if(_actFpMode == 3) { + string s = _params[_fplPos + i - 1]; + _kln89->DrawText(s, 2, 15-s.size(), 3-i); + _kln89->DrawSpecialChar(0, 2, 15, 3-i); + } + } + //cout << "F2c" << endl; + } + //cout << "F3" << endl; + } + //cout << "GGGGGG" << endl; + } else { // Not active flightplan + //cout << "Top pos is " << _fplPos << ' '; + // For synatical convienience + //int nWp = (_subPage == 0 && !_delFP ? 4 : 3); // number of waypoints to display + vector waylist = _kln89->_flightPlans[_subPage]->waypoints; + if(waylist.empty()) { + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1 && _kln89->_blink)) { + _kln89->DrawText(_delFP ? "Delete FPL?" : "Copy FPL 0?", 2, 0, 3); + } + } else { + if(!(_kln89->_mode == KLN89_MODE_CRSR && (_uLinePos == 1 || _uLinePos == 2) && _kln89->_blink)) { + _kln89->DrawText(_delFP ? "Delete FPL?" : "Use?", 2, 0, 3); + } + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2 && _kln89->_blink)) { + if(!_delFP) _kln89->DrawText("Inverted?", 2, 5, 3); + } + } + + // ---------------------------------- + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_uLinePos == 1) { + if(!_kln89->_blink) { + _kln89->Underline(2, 0, 3, (waylist.empty() || _delFP ? 11 : 4)); // This underline is blinked + _kln89->DrawEnt(); + } + } else if(_uLinePos == 2) { + // assert(!waylist.empty()); + if(!_kln89->_blink) { + _kln89->Underline(2, 0, 3, 14); // This underline is blinked + _kln89->DrawEnt(); + } + } else if(_uLinePos == 3) { + _kln89->Underline(2, 13, 2, 3); + } else if(_uLinePos >= 4) { + if(_bEntWp) { + if(_wLinePos == 0) { + _kln89->Underline(2, 5, 2 - (_uLinePos - 4), 4); + } else if(_wLinePos == 4) { + _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 4); + } else { + _kln89->Underline(2, 4, 2 - (_uLinePos - 4), _wLinePos); + _kln89->Underline(2, 5 + _wLinePos, 2 - (_uLinePos - 4), 4 - _wLinePos); + } + if(!_kln89->_blink) { + //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos); + _kln89->DrawEnt(); + } + } else { + if(!_delWp) _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 5); + } + } + } + // ---------------------------------- + + _kln89->DrawChar('>', 2, 12, 2); + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) DrawFpMode(2); + // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off + if((int)_fplPos > ((int)waylist.size()) - 2) _fplPos = (((int)waylist.size()) - 2 < 0 ? 0 : waylist.size() - 2); + unsigned int last_pos; + if(waylist.empty()) { + last_pos = 0; + } else { + last_pos = ((int)_fplPos == ((int)waylist.size()) - 2 ? waylist.size() : waylist.size() - 1); + } + if(waylist.size() < 3) last_pos = waylist.size(); + for(unsigned int i=0; i<3; ++i) { + string s = GPSitoa(i < 2 ? _fplPos + i + 1 : last_pos + 1); + s += ':'; + if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - s.size(), 2 - i); + bool drawID = true; + if(_delWp && _uLinePos == i+4) { + if(!_kln89->_blink) { + _kln89->DrawText("Del", 2, 0, 2-i); + _kln89->DrawChar('?', 2, 10, 2-i); + _kln89->Underline(2, 0, 2-i, 11); + _kln89->DrawEnt(); + } + } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) { + if(!_kln89->_blink) { + if(_wLinePos >= _entWp->id.size()) { + _kln89->DrawText(_entWp->id, 2, 4, 2-i); + _kln89->DrawChar(' ', 2, 4+_wLinePos, 2-i, false, true); + } else { + _kln89->DrawText(_entWp->id.substr(0, _wLinePos), 2, 4, 2-i); + _kln89->DrawChar(_entWp->id[_wLinePos], 2, 4+_wLinePos, 2-i, false, true); + _kln89->DrawText(_entWp->id.substr(_wLinePos+1, _entWp->id.size()-_wLinePos-1), 2, 5+_wLinePos, 2-i); + } + } + drawID = false; + } + if(drawID) { + if(i == 2 || _fplPos + i == waylist.size()) { + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) { + _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos]->id : "_____", 2, 4, 2-i); + } + if(last_pos > 0 && last_pos < waylist.size() && i > 0) { + // Draw the param + if(_fpMode == 0) { + string s = _params[last_pos - 1]; + _kln89->DrawText(s, 2, 16-s.size(), 2-i); + } + } + break; + } else { + if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) { + _kln89->DrawText(waylist[_fplPos+i]->id, 2, 4, 2-i); + } + if(i > 0) { + // Draw the param + if(_fpMode == 0) { + string s = _params[_fplPos + i - 1]; + _kln89->DrawText(s, 2, 16-s.size(), 2-i); + } + } + } + } + } + } + + KLN89Page::Update(dt); +} + +void KLN89FplPage::DrawFpMode(int ypos) { + string s = "Dis"; + if(0 == _subPage) { + if(_actFpMode == 1) { + s = "ETE"; + } else if(_actFpMode == 2) { + s = "UTC"; // TODO - alter depending on chosen timezone + } else if(_actFpMode == 3) { + s = (_kln89->_obsMode ? "OBS" : "Dtk"); + } + } else { + if(_fpMode == 1) { + s = "Dtk"; + } + } + _kln89->DrawText(s, 2, 13, ypos); +} + +// Bit of an ipsy-dipsy function this one - calc the required parameters for the displayed flightplan. +void KLN89FplPage::Calc() { + _params.clear(); + GPSFlightPlan* fp = _kln89->_flightPlans[_subPage]; + vector wv = fp->waypoints; + if(0 == _subPage) { + // Active FP - parameters are only displayed for the active waypoint onwards for the active plan, + // and distance is cumulative from the user position. + if(0 == _actFpMode) { + // Dis + double cum_tot = 0.0; + if(wv.size() > 0) { + //cum_tot += _kln89->GetHorizontalSeparation(_kln89->_gpsLat, _kln89->_gpsLon, wv[0]->lat, wv[0]->lon) * SG_METER_TO_NM; + cum_tot += _kln89->GetGreatCircleDistance(_kln89->_gpsLat, _kln89->_gpsLon, wv[0]->lat, wv[0]->lon); + } + for(unsigned int i=1; iGetHorizontalSeparation(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon) * SG_METER_TO_NM; // TODO - add units switch! + cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon); // TODO - add units switch! + int n = (int)(cum_tot + 0.5); + _params.push_back(GPSitoa(n)); + } + } else if(1 == _actFpMode) { + } else if(2 == _actFpMode) { + } else { + // Dtk + for(int i=1; iGetMagHeadingFromTo(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon); + int n = (int)(dtk + 0.5); + _params.push_back(GPSitoa(n)); + } + + } + } else { + // other FPs + if(0 == _fpMode) { + double cum_tot = 0.0; + for(int i=1; iGetHorizontalSeparation(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon) * SG_METER_TO_NM; // TODO - add units switch! + cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon); // TODO - add units switch! + int n = (int)(cum_tot + 0.5); + _params.push_back(GPSitoa(n)); + } + } else { + } + } +} + +void KLN89FplPage::CrsrPressed() { + if(_delFP) { + _delFP = false; + _kln89->_mode = KLN89_MODE_DISP; + return; + } + + _wLinePos = 0; + if(_kln89->_mode == KLN89_MODE_DISP) { + _fp0SelWpId.clear(); + if(_bEntWp) { + for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { + if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) { + _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i); + } + } + delete _entWp; + _entWp = NULL; + _bEntWp = false; + _entWpStr.clear(); + } + } else { + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + if(_kln89->_flightPlans[_subPage]->IsEmpty()) { + _uLinePos = 4; + } else { + _uLinePos = (_subPage == 0 ? 3 : 1); + } + } + } +} + +void KLN89FplPage::ClrPressed() { + if(_delFP) { + _kln89->_mode = KLN89_MODE_DISP; + _delFP = false; + } else if(_delAppr) { + _kln89->_mode = KLN89_MODE_DISP; + _delAppr = false; + } else { + if(KLN89_MODE_CRSR == _kln89->_mode) { + // TODO - see if we need to delete a waypoint + if(_uLinePos >= 4) { + if(_delWp) { + _kln89->_mode = KLN89_MODE_DISP; + _delWp = false; + } else { + // First check that we're not trying to delete an approach waypoint. Note that we can delete the approach by deleting the header though. + // Check for approach waypoints or header/fences in flightplan 0 + int n = _fplPos + _uLinePos - 4; + bool hdrPos = false; + bool fencePos = false; + //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n'; + if(n == _hdrPos) { + //cout << "HEADER POS\n"; + hdrPos = true; + } + if(n == _fencePos) { + //cout << "FENCE POS\n"; + fencePos = true; + } + if(_hdrPos >= 0 && n > _hdrPos) --n; + if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above! + //cout << "New n = " << n << '\n'; + if(hdrPos) { + //cout << "HDRP\n"; + _delAppr = true; + } else if(fencePos) { + //cout << "FENP\n"; + // no-op + } else if(n >= _kln89->_flightPlans[_subPage]->waypoints.size()) { + // no-op - off the end of the list on the entry field + } else if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType == GPS_APP_NONE) { + //cout << "DELFP\n"; + _kln89->_mode = KLN89_MODE_CRSR; + _delWp = true; + } else { + ShowScratchpadMessage("Invald", " Del "); + } + } + } else if(_uLinePos == 3) { + if(_subPage == 0) { + _actFpMode++; + if(_actFpMode > 3) _actFpMode = 0; + } else { + _fpMode++; + if(_fpMode > 1) _fpMode = 0; + } + } + } else { + _delFP = true; + _uLinePos = 1; + _kln89->_mode = KLN89_MODE_CRSR; + } + } +} + +void KLN89FplPage::CleanUp() { + // TODO - possibly need to clean up _delWp here as well, since it goes off if dto and then ent are pressed. + + _bEntWp = false; + for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { + if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) { + _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i); + } + } + delete _entWp; + _entWp = NULL; + _entWpStr.clear(); + KLN89Page::CleanUp(); +} + +void KLN89FplPage::LooseFocus() { + _fplPos = 0; + _resetFplPos0 = true; + _wLinePos = 0; + _uLinePos = 0; + _fp0SelWpId.clear(); + _scratchpadMsg = false; +} + +void KLN89FplPage::EntPressed() { + if(_delFP) { + _parent->ClearFlightPlan(_subPage); + CrsrPressed(); + } else if(_delWp) { + int pos = _uLinePos - 4 + _fplPos; + // Sanity check - the calculated wp position should never be off the end of the waypoint list. + if(pos > _kln89->_flightPlans[_subPage]->waypoints.size() - 1) { + cout << "ERROR - _uLinePos too big in KLN89FplPage::EntPressed!\n"; + return; + } + _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + pos); + _delWp = false; + // Do we need to re-calc _fplPos here? + } else if(_bEntExp) { + _bEntWp = false; + _bEntExp = false; + _entWp = NULL; // DON'T delete it! - it's been pushed onto the waypoint list at this point. + _entWpStr.clear(); + _kln89->_cleanUpPage = -1; + _wLinePos = 0; + // TODO - in actual fact the previously underlined waypoint stays in the same position and underlined + // in some or possibly all circumstances - need to check this out and match it, but not too important + // for now. + } else if(_bEntWp) { + if(_entWp != NULL) { + // TODO - should be able to get rid of this switch I think and use the enum values. + switch(_entWp->type) { + case GPS_WP_APT: + _kln89->_activePage = _kln89->_pages[0]; + _kln89->_curPage = 0; + ((KLN89Page*)_kln89->_pages[0])->SetEntInvert(true); + break; + case GPS_WP_VOR: + _kln89->_activePage = _kln89->_pages[1]; + _kln89->_curPage = 1; + ((KLN89Page*)_kln89->_pages[1])->SetEntInvert(true); + break; + case GPS_WP_NDB: + _kln89->_activePage = _kln89->_pages[2]; + _kln89->_curPage = 2; + ((KLN89Page*)_kln89->_pages[2])->SetEntInvert(true); + break; + case GPS_WP_INT: + _kln89->_activePage = _kln89->_pages[3]; + _kln89->_curPage = 3; + ((KLN89Page*)_kln89->_pages[3])->SetEntInvert(true); + break; + case GPS_WP_USR: + _kln89->_activePage = _kln89->_pages[4]; + _kln89->_curPage = 4; + ((KLN89Page*)_kln89->_pages[4])->SetEntInvert(true); + break; + default: + cout << "Error - unknown waypoint type found in KLN89::FplPage::EntPressed()\n"; + } + _kln89->_activePage->SetId(_entWp->id); + _kln89->_entJump = 7; + _kln89->_cleanUpPage = 7; + _kln89->_entRestoreCrsr = true; + _kln89->_mode = KLN89_MODE_DISP; + } + _bEntExp = true; + } else if(_uLinePos == 1) { + if(_kln89->_flightPlans[_subPage]->IsEmpty()) { + // Copy fpl 0 + for(unsigned int i=0; i<_kln89->_flightPlans[0]->waypoints.size(); ++i) { + GPSWaypoint* wp = new GPSWaypoint; + *wp = *(_kln89->_flightPlans[0]->waypoints[i]); + _kln89->_flightPlans[_subPage]->waypoints.push_back(wp); + } + } else { + // Use + _parent->ClearFlightPlan(0); + for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { + GPSWaypoint* wp = new GPSWaypoint; + *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]); + _kln89->_flightPlans[0]->waypoints.push_back(wp); + } + _kln89->OrientateToActiveFlightPlan(); + _subPage = 0; + } + _parent->CrsrPressed(); + } else if(_uLinePos == 2) { + if(_kln89->_flightPlans[_subPage]->IsEmpty()) { + // ERROR !!! + } else { + // Use Invert + _parent->ClearFlightPlan(0); + for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) { + GPSWaypoint* wp = new GPSWaypoint; + *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]); + // FIXME - very inefficient - use a reverse iterator on the source array and push_back instead!!!!!!!! + _kln89->_flightPlans[0]->waypoints.insert(_kln89->_flightPlans[0]->waypoints.begin(), wp); + } + _kln89->OrientateToActiveFlightPlan(); + } + _parent->CrsrPressed(); + _subPage = 0; + } +} + +void KLN89FplPage::Knob1Left1() { + if(_delFP) { + _delFP = false; + return; + } + _delWp = false; + _changeAppr = false; + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_bEntWp) { + if(_wLinePos > 0) _wLinePos--; + } else { + // _uLinePos with empty/not-empty plan: 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+ + if(_uLinePos == 0) { + // No-op + } else if(_uLinePos == 1 || _uLinePos == 2) { + _uLinePos--; + } else if(_uLinePos == 3) { + _uLinePos = 4; + } else if(_uLinePos == 4) { + if(_kln89->_flightPlans[_subPage]->IsEmpty()) { + _uLinePos = (_subPage == 0 ? 0 : 1); + } else if(_fplPos == 0) { + _uLinePos = (_subPage == 0 ? 0 : 2); + } else { + _fplPos--; + } + } else if(_uLinePos == 5) { + _uLinePos = 3; + } else { + _uLinePos--; + } + + if(_subPage == 0 && _uLinePos > 3) { + int ix = _fplPos + (_uLinePos - 4); + if(_fencePos >= 0 && ix >= _fencePos) ix--; + if(_hdrPos >= 0 && ix >= _hdrPos) ix--; + if(ix >= _kln89->_activeFP->waypoints.size()) { + _fp0SelWpId.clear(); + } else { + _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id; + } + } else { + _fp0SelWpId.clear(); + //cout << "Not page 0, or not in waypoints, clearing id!\n"; + } + } + } +} + +void KLN89FplPage::Knob1Right1() { + if(_delFP) { + _delFP = false; + return; + } + _delWp = false; + _changeAppr = false; + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_bEntWp) { + if(_wLinePos < 4) _wLinePos++; + } else { + // _uLinePos with empty/not-empty plan: + // 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+ + if(_uLinePos == 0) { + _uLinePos = (_subPage == 0 ? 4 : 1); + } else if(_uLinePos == 1) { + _uLinePos = (_kln89->_flightPlans[_subPage]->IsEmpty() ? 4 : 2); + } else if(_uLinePos == 2) { + _uLinePos = 4; + } else if(_uLinePos == 3) { + if(!_kln89->_flightPlans[_subPage]->IsEmpty()) _uLinePos = 5; + } else if(_uLinePos == 4) { + _uLinePos = 3; + } else if((_subPage == 0 && _uLinePos == 6) || (_subPage > 0 && _uLinePos == 5)) { + // Urrggh - complicated! + // 3 possibilities: + // 1: We're on the entry field at the end of the list, and can't move any more. + // 2: We're on the last or second-last field, and move to the last position + // 3: We're on a field before the second-last one, and don't move, but change the list-head position + // And 4: _subPage 0 can be complicated by the presence of header/fence lines in an approach. + int hfcount = 0; + if(_subPage == 0) { + if(_hdrPos >= 0) hfcount++; + if(_fencePos >= 0) hfcount++; + } + if(_kln89->_flightPlans[_subPage]->waypoints.size() == 1 || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() + hfcount - 1) { + // 1: Don't move + } else if(_fplPos >= _kln89->_flightPlans[_subPage]->waypoints.size() + hfcount - (_subPage == 0 ? 4 : 3)) { + _uLinePos++; + } else { + _fplPos++; + } + } else if(_uLinePos == 5) { + // Must be _subPage 0 + _uLinePos++; + } else { + // Must be the last line - either _uLinePos 6 or 7 depending on _subPage + int thresh = (_subPage == 0 ? 3 : 2); + if(_kln89->_flightPlans[_subPage]->waypoints.size() == thresh || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() - thresh) { + // Don't move + } else { + _fplPos++; + } + } + + if(_subPage == 0 && _uLinePos > 3) { + int ix = _fplPos + (_uLinePos - 4); + if(_fencePos >= 0 && ix >= _fencePos) ix--; + if(_hdrPos >= 0 && ix >= _hdrPos) ix--; + if(ix >= _kln89->_activeFP->waypoints.size()) { + _fp0SelWpId.clear(); + } else { + _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id; + } + } else { + _fp0SelWpId.clear(); + //cout << "Not page 0, or not in waypoints, clearing id!\n"; + } + } + } +} + +void KLN89FplPage::Knob2Left1() { + if(_delFP) { + _delFP = false; + return; + } + _delWp = false; + + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true; + KLN89Page::Knob2Left1(); + } else { + if(_uLinePos > 3) { + // Check for approach waypoints or header/fences in flightplan 0 + int n = _fplPos + _uLinePos - 4; + bool hdrPos = false; + bool fencePos = false; + bool appWp = false; + //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n'; + if(n == _hdrPos) { + //cout << "HEADER POS\n"; + hdrPos = true; + } + if(n == _fencePos) { + //cout << "FENCE POS\n"; + fencePos = true; + } + if(_hdrPos >= 0 && n > _hdrPos) --n; + if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above! + //cout << "New n = " << n << '\n'; + + if(n < _kln89->_flightPlans[_subPage]->waypoints.size()) { + if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) { + appWp = true; + } + } + + if(hdrPos) { + // TODO - not sure what we actually do in this condition + _changeAppr = true; + } else if(fencePos) { + // no-op? + } else if(appWp) { + ShowScratchpadMessage("Invald", " Add "); + } else { + if((_wLinePos + 1) > _entWpStr.size()) { + _entWpStr += '9'; + } else { + _entWpStr[_wLinePos] = _kln89->DecChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true)); + } + _bEntWp = true; + _fp0SelWpId.clear(); // Waypoints don't become the DTO default whilst being entered. + + bool multi; + const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false); + if(NULL == wp) { + // no-op + } else { + if(_entWp == NULL) { + _entWp = new GPSWaypoint; + if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) { + _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp); + } else { + _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp); + } + } + // copy + *_entWp = *wp; + } + } + } + } +} + +void KLN89FplPage::Knob2Right1() { + if(_delFP) { + _delFP = false; + return; + } + _delWp = false; + + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true; + KLN89Page::Knob2Right1(); + } else { + if(_uLinePos > 3) { + // Check for approach waypoints or header/fences in flightplan 0 + int n = _fplPos + _uLinePos - 4; + bool hdrPos = false; + bool fencePos = false; + bool appWp = false; + //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n'; + if(n == _hdrPos) { + //cout << "HEADER POS\n"; + hdrPos = true; + } + if(n == _fencePos) { + //cout << "FENCE POS\n"; + fencePos = true; + } + if(_hdrPos >= 0 && n > _hdrPos) --n; + if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above! + //cout << "New n = " << n << '\n'; + + if(n < _kln89->_flightPlans[_subPage]->waypoints.size()) { + if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) { + appWp = true; + } + } + + if(hdrPos) { + // TODO - not sure what we actually do in this condition + _changeAppr = true; + } else if(fencePos) { + // no-op? + } else if(appWp) { + ShowScratchpadMessage("Invald", " Add "); + } else { + if((_wLinePos + 1) > _entWpStr.size()) { + _entWpStr += '9'; + } else { + _entWpStr[_wLinePos] = _kln89->DecChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true)); + } + _bEntWp = true; + _fp0SelWpId.clear(); // Waypoints don't become the DTO default whilst being entered. + + bool multi; + const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false); + if(NULL == wp) { + // no-op + } else { + if(_entWp == NULL) { + _entWp = new GPSWaypoint; + if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) { + _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp); + } else { + _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp); + } + } + // copy + *_entWp = *wp; + } + } + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_fpl.hxx b/src/Instrumentation/KLN89/kln89_page_fpl.hxx new file mode 100644 index 000000000..a571e16d6 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_fpl.hxx @@ -0,0 +1,91 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_FPL_HXX +#define _KLN89_PAGE_FPL_HXX + +#include "kln89.hxx" + +class KLN89FplPage : public KLN89Page { + +public: + KLN89FplPage(KLN89* parent); + ~KLN89FplPage(); + + void Update(double dt); + + void CrsrPressed(); + void EntPressed(); + void ClrPressed(); + void Knob1Left1(); + void Knob1Right1(); + void Knob2Left1(); + void Knob2Right1(); + + void CleanUp(); + void LooseFocus(); + + // Override the base class GetId function to return the waypoint ID under the cursor + // on FPL0 page, if there is one and the cursor is on. + // Otherwise return an empty string. + inline string GetId() { return(_fp0SelWpId); } + +private: + int _fpMode; // 0 = Dis, 1 = Dtk + int _actFpMode; // 0 = Dis, 1 = ETE, 2 = ETA, 3 = Dtk/OBS + + bool _bEntWp; // set true when a waypoint is being entered + bool _bEntExp; // Set true when ent is expected to set the currently entered waypoint as entered. + string _entWpStr; // The currently entered wp ID (need not be valid) + GPSWaypoint* _entWp; // Waypoint being currently entered + + // The position of the cursor in a waypoint being entered + unsigned int _wLinePos; + + unsigned int _fplPos; // The position of the start of the FP (NOT the active one) (zero-based). + // since this is reset when subpage changes we only need 1, not an array of 25! + bool _resetFplPos0; // Set true when a recalculation of _fplPos for the active flightplan page is required. + + int _hdrPos; + int _fencePos; + + // Get the waypoint (returned thru the pointer) at the zero-based position (pos) + // in the waypoint display of the current page. + // Returns 0 if no waypoint, 1 if sucessfull, 2 if appr header, 3 if approach fence. + //int GetFPWaypoint(GPSWaypoint* wp, int pos); + + bool _delFP; // Set true when the delete FP? dialogue is being displayed + bool _delWp; // The position of the waypoint to delete is given by _uLinePos + bool _delAppr; // Set true when the delete approach dialogue is being displayed + bool _changeAppr; + + void DrawFpMode(int ypos); + void Calc(); + + // The ID of the waypoint under the cursor in fpl0, if those conditions exist! + string _fp0SelWpId; + + vector _params; +}; + +#endif // _KLN89_PAGE_FPL_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_int.cxx b/src/Instrumentation/KLN89/kln89_page_int.cxx new file mode 100644 index 000000000..e765cffc7 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_int.cxx @@ -0,0 +1,242 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_int.hxx" + +KLN89IntPage::KLN89IntPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 2; + _subPage = 0; + _name = "INT"; + _int_id = "PORTE"; + _last_int_id = ""; + _fp = NULL; + _nearestVor = NULL; + _refNav = NULL; +} + +KLN89IntPage::~KLN89IntPage() { +} + +void KLN89IntPage::Update(double dt) { + bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false); + bool multi; // Not set by FindFirst... + bool exact = false; + if(_int_id.size() == 5) exact = true; + if(_fp == NULL) { + _fp = _kln89->FindFirstIntById(_int_id, multi, exact); + } else if(_fp->get_ident() != _int_id) { + _fp = _kln89->FindFirstIntById(_int_id, multi, exact); + } + + if(_fp) { + _int_id = _fp->get_ident(); + if(_kln89->GetActiveWaypoint()) { + if(_int_id == _kln89->GetActiveWaypoint()->id) { + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + // Active waypoint arrow + _kln89->DrawSpecialChar(4, 2, 0, 3); + } + } + } + if(_int_id != _last_int_id) { + _nearestVor = _kln89->FindClosestVor(_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS); + if(_nearestVor) { + _nvRadial = _kln89->GetMagHeadingFromTo(_nearestVor->get_lat() * SG_DEGREES_TO_RADIANS, _nearestVor->get_lon() * SG_DEGREES_TO_RADIANS, + _fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS); + _nvDist = _kln89->GetGreatCircleDistance(_nearestVor->get_lat() * SG_DEGREES_TO_RADIANS, _nearestVor->get_lon() * SG_DEGREES_TO_RADIANS, + _fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS); + _refNav = _nearestVor; // TODO - check that this *always* holds - eg. when changing INT id after explicitly setting ref nav + // but with no loss of focus. + } else { + _refNav = NULL; + } + _last_int_id = _int_id; + } + if(_kln89->_mode != KLN89_MODE_CRSR) { + if(!_entInvert) { + if(!actPage) { + _kln89->DrawText(_fp->get_ident(), 2, 1, 3); + } else { + // If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index. + _kln89->DrawText(_fp->get_ident(), 2, 4, 3); + char buf[3]; + int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1); + _kln89->DrawText((string)buf, 2, 3 - n, 3); + // We also draw an I to differentiate INT from USR when it's the ACT page + _kln89->DrawText("I", 2, 11, 3); + } + } else { + if(!_kln89->_blink) { + _kln89->DrawText(_fp->get_ident(), 2, 1, 3, false, 99); + _kln89->DrawEnt(); + } + } + } + if(_subPage == 0) { + _kln89->DrawLatitude(_fp->get_lat(), 2, 3, 2); + _kln89->DrawLongitude(_fp->get_lon(), 2, 3, 1); + _kln89->DrawDirDistField(_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS, 2, 0, 0, + _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 6 ? true : false)); + } else { + _kln89->DrawText("Ref:", 2, 1, 2); + _kln89->DrawText("Rad:", 2, 1, 1); + _kln89->DrawText("Dis:", 2, 1, 0); + if(_refNav) { + _kln89->DrawText(_refNav->get_ident(), 2, 9, 2); // TODO - flash and allow to change if under cursor + //_kln89->DrawHeading(_nvRadial, 2, 11, 1); + //_kln89->DrawDist(_nvDist, 2, 11, 0); + // Currently our draw heading and draw dist functions don't do as many decimal points as we want here, + // so draw it ourselves! + // Heading + char buf[10]; + snprintf(buf, 6, "%.1f", _nvRadial); + string s = buf; + _kln89->DrawText(s, 2, 13 - s.size(), 1); + _kln89->DrawSpecialChar(0, 2, 13, 1); // Degrees symbol + // Dist + double d = _nvDist; + d *= (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001); + snprintf(buf, 9, "%.1f", d); + s = buf; + s += (_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "Km"); + _kln89->DrawText(s, 2, 14 - s.size(), 0); + } + } + } else { + // TODO - when we leave the page with invalid id and return it should + // revert to showing the last valid id. Same for vor/ndb/probably apt etc. + if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_int_id, 2, 1, 3); + if(_subPage == 0) { + _kln89->DrawText("- -- --.--'", 2, 3, 2); + _kln89->DrawText("---- --.--'", 2, 3, 1); + _kln89->DrawSpecialChar(0, 2, 7, 2); + _kln89->DrawSpecialChar(0, 2, 7, 1); + _kln89->DrawText(">--- ----", 2, 0, 0); + _kln89->DrawSpecialChar(0, 2, 4, 0); + _kln89->DrawText(_to_flag ? "To" : "Fr", 2, 5, 0); + _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 12, 0); + } + } + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_uLinePos > 0 && _uLinePos < 6) { + // TODO - blink as well + _kln89->Underline(2, _uLinePos, 3, 1); + } + for(unsigned int i = 0; i < _int_id.size(); ++i) { + if(_uLinePos != (i + 1)) { + _kln89->DrawChar(_int_id[i], 2, i + 1, 3); + } else { + if(!_kln89->_blink) _kln89->DrawChar(_int_id[i], 2, i + 1, 3); + } + } + } + + // TODO - fix this duplication - use _id instead of _apt_id, _vor_id, _ndb_id, _int_id etc! + _id = _int_id; + + KLN89Page::Update(dt); +} + +void KLN89IntPage::SetId(string s) { + _last_int_id = _int_id; + _save_int_id = _int_id; + _int_id = s; + _fp = NULL; +} + +void KLN89IntPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) return; + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + _uLinePos = 1; + } + if(_subPage == 0) { + _maxULinePos = 6; + } else { + _maxULinePos = 6; + } +} + +void KLN89IntPage::ClrPressed() { + if(_subPage == 0 && _uLinePos == 6) { + _to_flag = !_to_flag; + } +} + +void KLN89IntPage::EntPressed() { + if(_entInvert) { + _entInvert = false; + _last_int_id = _int_id; + _int_id = _save_int_id; + } +} + +void KLN89IntPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Left1(); + } else { + if(_uLinePos < 6) { + // Same logic for both pages - set the ID + _int_id = _int_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_int_id.size() + 1)) { + _int_id += '9'; + } else { + _int_id[_uLinePos - 1] = _kln89->DecChar(_int_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // NO-OP - from/to field is switched by clr button, not inner knob. + } else { + // TODO - LNR type field. + } + } + } +} + +void KLN89IntPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Right1(); + } else { + if(_uLinePos < 6) { + // Same logic for both pages - set the ID + _int_id = _int_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_int_id.size() + 1)) { + _int_id += 'A'; + } else { + _int_id[_uLinePos - 1] = _kln89->IncChar(_int_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // NO-OP - from/to field is switched by clr button, not inner knob. + } else { + // TODO - LNR type field. + } + } + } +} + diff --git a/src/Instrumentation/KLN89/kln89_page_int.hxx b/src/Instrumentation/KLN89/kln89_page_int.hxx new file mode 100644 index 000000000..f8b8dc7a2 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_int.hxx @@ -0,0 +1,56 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_INT_HXX +#define _KLN89_PAGE_INT_HXX + +#include "kln89.hxx" + +class KLN89IntPage : public KLN89Page { + +public: + KLN89IntPage(KLN89* parent); + ~KLN89IntPage(); + + void Update(double dt); + + void CrsrPressed(); + void ClrPressed(); + void EntPressed(); + void Knob2Left1(); + void Knob2Right1(); + + void SetId(string s); + +private: + string _int_id; + string _last_int_id; + string _save_int_id; + const FGFix* _fp; + FGNavRecord* _nearestVor; + FGNavRecord* _refNav; // Will usually be the same as _nearestVor, and gets reset to _nearestVor when page looses focus. + double _nvRadial; // radial from nearest VOR + double _nvDist; // distance to nearest VOR +}; + +#endif // _KLN89_PAGE_INT_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_nav.cxx b/src/Instrumentation/KLN89/kln89_page_nav.cxx new file mode 100644 index 000000000..0cd1e579f --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_nav.cxx @@ -0,0 +1,513 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_nav.hxx" + +KLN89NavPage::KLN89NavPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 4; + _subPage = 0; + _name = "NAV"; + _posFormat = 0; // Check - should this default to ref from waypoint? + _vnv = 0; + _nav4DataSnippet = 0; + _cdiFormat = 0; + _menuActive = false; + _menuPos = 0; + _suspendAVS = false; +} + +KLN89NavPage::~KLN89NavPage() { +} + +void KLN89NavPage::Update(double dt) { + GPSFlightPlan* fp = ((KLN89*)_parent)->_activeFP; + GPSWaypoint* awp = _parent->GetActiveWaypoint(); + bool crsr = (_kln89->_mode == KLN89_MODE_CRSR); + bool blink = _kln89->_blink; + double lat = _kln89->_gpsLat * SG_RADIANS_TO_DEGREES; + double lon = _kln89->_gpsLon * SG_RADIANS_TO_DEGREES; + + if(0 == _subPage) { + if(_kln89->_navFlagged) { + _kln89->DrawText("> F L A G", 2, 0, 2); + _kln89->DrawText("DTK --- TK ---", 2, 0, 1); + _kln89->DrawText(">--- To --:--", 2, 0, 0); + _kln89->DrawSpecialChar(0, 2, 7, 1); + _kln89->DrawSpecialChar(0, 2, 15, 1); + _kln89->DrawSpecialChar(0, 2, 4, 0); + _kln89->DrawSpecialChar(1, 2, 3, 2); + _kln89->DrawSpecialChar(1, 2, 4, 2); + _kln89->DrawSpecialChar(1, 2, 6, 2); + _kln89->DrawSpecialChar(1, 2, 10, 2); + _kln89->DrawSpecialChar(1, 2, 12, 2); + _kln89->DrawSpecialChar(1, 2, 13, 2); + } else { + if(_kln89->_dto) { + _kln89->DrawDTO(2, 7, 3); + } else { + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + _kln89->DrawSpecialChar(3, 2, 8, 3); + } + } + _kln89->DrawText(awp->id, 2, 10, 3); + if(!_kln89->_dto && !_kln89->_obsMode && !_kln89->_fromWaypoint.id.empty()) { + _kln89->DrawText(_kln89->_fromWaypoint.id, 2, 1, 3); + } + if(!(crsr && blink && _uLinePos == 1)) { + if(_cdiFormat == 0) { + _kln89->DrawCDI(); + } else if(_cdiFormat == 1) { + _kln89->DrawText("Fly", 2, 2, 2); + double x = _kln89->CalcCrossTrackDeviation(); + // TODO - check the R/L from sign of x below - I *think* it holds but not sure! + // Note also that we're setting Fly R or L based on the aircraft + // position only, not the heading. Not sure if this is correct or not. + _kln89->DrawText(x < 0.0 ? "R" : "L", 2, 6, 2); + char buf[6]; + int n; + x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001)); + if(x < 1.0) { + n = snprintf(buf, 6, "%0.2f", x); + } else if(x < 100.0) { + n = snprintf(buf, 6, "%0.1f", x); + } else { + n = snprintf(buf, 6, "%i", (int)(x+0.5)); + } + _kln89->DrawText((string)buf, 2, 13-n, 2); + _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 13, 2); + } else { + _kln89->DrawText("CDI Scale:", 2, 1, 2); + double d = _kln89->_cdiScales[_kln89->_currentCdiScaleIndex] * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001); + char buf[5]; + string s; + if(d >= 1.0) { + snprintf(buf, 4, "%2.1f", d); + s = buf; + } else { + snprintf(buf, 5, "%2.2f", d); + // trim the leading zero + s = buf; + s = s.substr(1, s.size() - 1); + } + _kln89->DrawText(s, 2, 11, 2); + _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 14, 2); + } + } + _kln89->DrawChar('>', 2, 0, 2); + _kln89->DrawChar('>', 2, 0, 0); + if(crsr) { + if(_uLinePos == 1) _kln89->Underline(2, 1, 2, 15); + else if(_uLinePos == 2) _kln89->Underline(2, 1, 0, 9); + } + // Desired and actual magnetic track + if(!_kln89->_obsMode) { + _kln89->DrawText("DTK", 2, 0, 1); + _kln89->DrawHeading(_kln89->_dtkMag, 2, 7, 1); + } + _kln89->DrawText("TK", 2, 9, 1); + if(_kln89->_groundSpeed_ms > 3) { // about 6 knots, don't know exactly what value to disable track + // The trouble with relying on FG gps's track value is we don't know when it's valid. + _kln89->DrawHeading(_kln89->_magTrackDeg, 2, 15, 1); + } else { + _kln89->DrawText("---", 2, 12, 1); + _kln89->DrawSpecialChar(0, 2, 15, 1); + } + + // Radial to/from active waypoint. + // TODO - Not sure if this either is or should be true or mag!!!!!!! + if(!(crsr && blink && _uLinePos == 2)) { + if(0 == _vnv) { + _kln89->DrawHeading((int)_kln89->GetHeadingToActiveWaypoint(), 2, 4, 0); + _kln89->DrawText("To", 2, 5, 0); + } else if(1 == _vnv) { + _kln89->DrawHeading((int)_kln89->GetHeadingFromActiveWaypoint(), 2, 4, 0); + _kln89->DrawText("Fr", 2, 5, 0); + } else { + _kln89->DrawText("Vnv Off", 2, 1, 0); + } + } + // It seems that the floating point groundspeed must be at least 30kt + // for an ETA to be calculated. Note that this means that (integer) 30kt + // can appear in the frame 1 display both with and without an ETA displayed. + // TODO - need to switch off track (and heading bug change) based on instantaneous speed as well + // since the long gps lag filter means we can still be displaying when stopped on ground. + if(_kln89->_groundSpeed_kts > 30.0) { + // Assuming eta display is always hh:mm + // Does it ever switch to seconds when close? + if(_kln89->_eta / 3600.0 > 100.0) { + // More that 100 hours ! - Doesn't fit. + _kln89->DrawText("--:--", 2, 11, 0); + } else { + _kln89->DrawTime(_kln89->_eta, 2, 15, 0); + } + } else { + _kln89->DrawText("--:--", 2, 11, 0); + } + } + } else if(1 == _subPage) { + // Present position + _kln89->DrawChar('>', 2, 1, 3); + if(!(crsr && blink && _uLinePos == 1)) _kln89->DrawText("PRESENT POSN", 2, 2, 3); + if(crsr && _uLinePos == 1) _kln89->Underline(2, 2, 3, 12); + if(0 == _posFormat) { + // Lat/lon + _kln89->DrawLatitude(lat, 2, 3, 1); + _kln89->DrawLongitude(lon, 2, 3, 0); + } else { + // Ref from wp - defaults to nearest vor (and resets to default when page left and re-entered). + } + } else if(2 == _subPage) { + _kln89->DrawText("Time", 2, 0, 3); + // TODO - hardwired to UTC at the moment + _kln89->DrawText("UTC", 2, 6, 3); + string th = fgGetString("/instrumentation/clock/indicated-hour"); + string tm = fgGetString("/instrumentation/clock/indicated-min"); + if(th.size() == 1) th = "0" + th; + if(tm.size() == 1) tm = "0" + tm; + _kln89->DrawText(th + tm, 2, 11, 3); + _kln89->DrawText("Depart", 2, 0, 2); + _kln89->DrawText(_kln89->_departureTimeString, 2, 11, 2); + _kln89->DrawText("ETA", 2, 0, 1); + if(_kln89->_departed) { + /* Rules of ETA waypoint are: + If the active waypoint is part of the active flightplan, then display + the ETA to the final (destination) waypoint of the active flightplan. + If the active waypoint is not part of the active flightplan, then + display the ETA to the active waypoint. */ + // TODO - implement the above properly - we haven't below! + string wid = ""; + if(fp->waypoints.size()) { + wid = fp->waypoints[fp->waypoints.size() - 1]->id; + } else if(awp) { + wid = awp->id; + } + if(!wid.empty()) { + _kln89->DrawText(wid, 2, 4, 1); + double tsec = _kln89->GetTimeToWaypoint(wid); + if(tsec < 0.0) { + _kln89->DrawText("----", 2, 11, 1); + } else { + int etah = (int)tsec / 3600; + int etam = ((int)tsec - etah * 3600) / 60; + etah += atoi(fgGetString("/instrumentation/clock/indicated-hour")); + etam += atoi(fgGetString("/instrumentation/clock/indicated-min")); + while(etam > 59) { + etam -= 60; + etah += 1; + } + while(etah > 23) { + etah -= 24; + } + char buf[6]; + int n = snprintf(buf, 6, "%02i%02i", etah, etam); + _kln89->DrawText((string)buf, 2, 15-n, 1); + } + } else { + _kln89->DrawText("----", 2, 11, 1); + } + } else { + _kln89->DrawText("----", 2, 11, 1); + } + _kln89->DrawText("Flight", 2, 0, 0); + if(_kln89->_departed) { + int eh = (int)_kln89->_elapsedTime / 3600; + int em = ((int)_kln89->_elapsedTime - eh * 3600) / 60; + char buf[6]; + int n = snprintf(buf, 6, "%i:%02i", eh, em); + _kln89->DrawText((string)buf, 2, 15-n, 0); + } else { + _kln89->DrawText("-:--", 2, 11, 0); + } + } else { + // The moving map page the core KLN89 class draws this. + if(_kln89->_mapOrientation == 2 && _kln89->_groundSpeed_kts < 2) { + // Don't draw it if in track up mode and groundspeed < 2kts, as per real-life unit. + } else { + _kln89->DrawMap(!_suspendAVS); + } + // Now draw any annotation over it. + int scale = KLN89MapScales[_kln89->_mapScaleUnits][_kln89->_mapScaleIndex]; + string scle_str = GPSitoa(scale); + if(crsr) { + if(_menuActive) { + // Draw a background quad to encompass on/off for the first three at 'off' length + _kln89->DrawMapQuad(28, 9, 48, 36, true); + _kln89->DrawMapText("SUA:", 1, 27, true); + if(!(_menuPos == 0 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawSUA ? "on" : "off"), 29, 27, true); + if(_menuPos == 0) _kln89->DrawLine(28, 27, 48, 27); + _kln89->DrawMapText("VOR:", 1, 18, true); + if(!(_menuPos == 1 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawVOR ? "on" : "off"), 29, 18, true); + if(_menuPos == 1) _kln89->DrawLine(28, 18, 48, 18); + _kln89->DrawMapText("APT:", 1, 9, true); + if(!(_menuPos == 2 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawApt ? "on" : "off"), 29, 9, true); + if(_menuPos == 2) _kln89->DrawLine(28, 9, 48, 9); + _kln89->DrawMapQuad(0, 0, 27, 8, true); + if(!(_menuPos == 3 && _kln89->_blink)) { + if(_kln89->_mapOrientation == 0) { + _kln89->DrawMapText("N", 1, 0, true); + _kln89->DrawMapUpArrow(7, 1); + } else if(_kln89->_mapOrientation == 1) { + _kln89->DrawMapText("DTK", 1, 0, true); + _kln89->DrawMapUpArrow(21, 1); + } else { + // Don't bother with heading up for now! + _kln89->DrawMapText("TK", 1, 0, true); + _kln89->DrawMapUpArrow(14, 1); + } + } + if(_menuPos == 3) _kln89->DrawLine(0, 0, 27, 0); + } else { + if(_uLinePos == 2) { + if(!_kln89->_blink) { + _kln89->DrawMapText("Menu?", 1, 9, true); + _kln89->DrawEnt(); + _kln89->DrawLine(0, 9, 34, 9); + } else { + _kln89->DrawMapQuad(0, 9, 34, 17, true); + } + } else { + _kln89->DrawMapText("Menu?", 1, 9, true); + } + // right-justify the scale when _uLinePos == 3 + if(!(_uLinePos == 3 && _kln89->_blink)) _kln89->DrawMapText(scle_str, (_uLinePos == 3 ? 29 - (scle_str.size() * 7) : 1), 0, true); + if(_uLinePos == 3) _kln89->DrawLine(0, 0, 27, 0); + } + } else { + // Just draw the scale + _kln89->DrawMapText(scle_str, 1, 0, true); + } + // And do part of the field 1 update, since NAV 4 is a special case for the last line. + _kln89->DrawChar('>', 1, 0, 0); + if(crsr && _uLinePos == 1) _kln89->Underline(1, 1, 0, 5); + if(!(crsr && _uLinePos == 1 && _kln89->_blink)) { + if(_kln89->_obsMode && _nav4DataSnippet == 0) _nav4DataSnippet = 1; + double tsec; + switch(_nav4DataSnippet) { + case 0: + // DTK + _kln89->DrawLabel("DTK", -39, 6); + // TODO - check we have an active FP / dtk and draw dashes if not. + char buf0[4]; + snprintf(buf0, 4, "%03i", (int)(_kln89->_dtkMag)); + _kln89->DrawText((string)buf0, 1, 3, 0); + break; + case 1: + // groundspeed + _kln89->DrawSpeed(_kln89->_groundSpeed_kts, 1, 5, 0); + break; + case 2: + // ETE + tsec = _kln89->GetETE(); + if(tsec < 0.0) { + _kln89->DrawText("--:--", 1, 1, 0); + } else { + int eteh = (int)tsec / 3600; + int etem = ((int)tsec - eteh * 3600) / 60; + char buf[6]; + int n = snprintf(buf, 6, "%02i:%02i", eteh, etem); + _kln89->DrawText((string)buf, 1, 6-n, 0); + } + break; + case 3: + // Cross-track correction + double x = _kln89->CalcCrossTrackDeviation(); + if(x < 0.0) { + _kln89->DrawSpecialChar(3, 1, 5, 0); + } else { + _kln89->DrawSpecialChar(7, 1, 5, 0); + } + char buf3[6]; + int n; + x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001)); + if(x < 1.0) { + n = snprintf(buf3, 6, "%0.2f", x); + } else if(x < 100.0) { + n = snprintf(buf3, 6, "%0.1f", x); + } else { + n = snprintf(buf3, 6, "%i", (int)(x+0.5)); + } + _kln89->DrawText((string)buf3, 1, 5-n, 0); + break; + } + } + } + + KLN89Page::Update(dt); +} + +void KLN89NavPage::LooseFocus() { + _suspendAVS = false; +} + +void KLN89NavPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) { + // Crsr just switched off + _menuActive = false; + } else { + // Crsr just switched on + if(_subPage < 3) { + _uLinePos = 1; + } else { + _uLinePos = 3; + } + } +} + +void KLN89NavPage::EntPressed() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_subPage == 3 && _uLinePos == 2 && !_menuActive) { + _menuActive = true; + _menuPos = 0; + _suspendAVS = false; + } + } +} + +void KLN89NavPage::ClrPressed() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_subPage == 0) { + if(_uLinePos == 1) { + _cdiFormat++; + if(_cdiFormat > 2) _cdiFormat = 0; + } else if(_uLinePos == 2) { + _vnv++; + if(_vnv > 2) _vnv = 0; + } + } + if(_subPage == 3) { + if(_uLinePos > 1) { + _suspendAVS = !_suspendAVS; + _menuActive = false; + } else if(_uLinePos == 1) { + _nav4DataSnippet++; + if(_nav4DataSnippet > 3) _nav4DataSnippet = 0; + } + } + } else { + if(_subPage == 3) { + _suspendAVS = !_suspendAVS; + } + } +} + +void KLN89NavPage::Knob1Left1() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(!(_subPage == 3 && _menuActive)) { + if(_uLinePos > 0) _uLinePos--; + } else { + if(_menuPos > 0) _menuPos--; + } + } +} + +void KLN89NavPage::Knob1Right1() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_subPage < 2) { + if(_uLinePos < 2) _uLinePos++; + } else if(_subPage == 2) { + _uLinePos = 1; + } else { + // NAV 4 - this is complicated by whether the menu is displayed or not. + if(_menuActive) { + if(_menuPos < 3) _menuPos++; + } else { + if(_uLinePos < 3) _uLinePos++; + } + } + } +} + +void KLN89NavPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Left1(); + return; + } + if(_subPage == 0) { + if(_uLinePos == 1 && _cdiFormat == 2) { + _kln89->CDIFSDIncrease(); + } + } else if(_subPage == 3) { + if(_menuActive) { + if(_menuPos == 0) { + _kln89->_drawSUA = !_kln89->_drawSUA; + } else if(_menuPos == 1) { + _kln89->_drawVOR = !_kln89->_drawVOR; + } else if(_menuPos == 2) { + _kln89->_drawApt = !_kln89->_drawApt; + } else { + if(_kln89->_mapOrientation == 0) { + // Don't allow heading up for now + _kln89->_mapOrientation = 2; + } else { + _kln89->_mapOrientation--; + } + _kln89->UpdateMapHeading(); + } + } else if(_uLinePos == 3) { + // TODO - add AUTO + if(_kln89->_mapScaleIndex == 0) { + _kln89->_mapScaleIndex = 20; + } else { + _kln89->_mapScaleIndex--; + } + } + } +} + +void KLN89NavPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Right1(); + return; + } + if(_subPage == 0) { + if(_uLinePos == 1 && _cdiFormat == 2) { + _kln89->CDIFSDDecrease(); + } + } else if(_subPage == 3) { + if(_menuActive) { + if(_menuPos == 0) { + _kln89->_drawSUA = !_kln89->_drawSUA; + } else if(_menuPos == 1) { + _kln89->_drawVOR = !_kln89->_drawVOR; + } else if(_menuPos == 2) { + _kln89->_drawApt = !_kln89->_drawApt; + } else { + if(_kln89->_mapOrientation >= 2) { + // Don't allow heading up for now + _kln89->_mapOrientation = 0; + } else { + _kln89->_mapOrientation++; + } + _kln89->UpdateMapHeading(); + } + } else if(_uLinePos == 3) { + // TODO - add AUTO + if(_kln89->_mapScaleIndex == 20) { + _kln89->_mapScaleIndex = 0; + } else { + _kln89->_mapScaleIndex++; + } + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_nav.hxx b/src/Instrumentation/KLN89/kln89_page_nav.hxx new file mode 100644 index 000000000..7b722e335 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_nav.hxx @@ -0,0 +1,63 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89.hxx" + +class KLN89NavPage : public KLN89Page { + +public: + KLN89NavPage(KLN89* parent); + ~KLN89NavPage(); + + void Update(double dt); + + void CrsrPressed(); + void EntPressed(); + void ClrPressed(); + void Knob1Left1(); + void Knob1Right1(); + void Knob2Left1(); + void Knob2Right1(); + + void LooseFocus(); + +private: + int _posFormat; // 0 => lat,lon; 1 => ref to wp. + + int _vnv; // 0 => To, 1 => Fr, 2 => off. + + // The data snippet to be displayed in field 1 when the moving map is active (NAV 4) + int _nav4DataSnippet; // 0 => DTK, 1 => groundspeed, 2 => ETE, 3 => cross-track correction. + + // Format to draw in the CDI field. + // 0 => CDI, 1 => Cross track correction (eg " Fly R 2.15nm"), 2 => cdi scale (eg "CDI Scale:5.0nm") + int _cdiFormat; + + // Drawing of apt, vor and sua on the moving map can be temporarily suspended + // Note that this should be cleared when page focus is lost, or when the menu is displayed. + bool _suspendAVS; + + // NAV 4 menu stuff + bool _menuActive; + int _menuPos; +}; diff --git a/src/Instrumentation/KLN89/kln89_page_ndb.cxx b/src/Instrumentation/KLN89/kln89_page_ndb.cxx new file mode 100644 index 000000000..44698954b --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_ndb.cxx @@ -0,0 +1,205 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_ndb.hxx" + +KLN89NDBPage::KLN89NDBPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 2; + _subPage = 0; + _name = "NDB"; + _ndb_id = "SF"; + np = NULL; +} + +KLN89NDBPage::~KLN89NDBPage() { +} + +void KLN89NDBPage::Update(double dt) { + bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false); + bool multi; // Not set by FindFirst... + bool exact = false; + if(_ndb_id.size() == 3) exact = true; + if(np == NULL) { + np = _kln89->FindFirstNDBById(_ndb_id, multi, exact); + } else if(np->get_ident() != _ndb_id) { + np = _kln89->FindFirstNDBById(_ndb_id, multi, exact); + } + //if(np == NULL) cout << "NULL... "; + //if(b == false) cout << "false...\n"; + /* + if(np && b) { + cout << "VOR FOUND!\n"; + } else { + cout << ":-(\n"; + } + */ + if(np) { + //cout << np->id << '\n'; + _ndb_id = np->get_ident(); + if(_kln89->GetActiveWaypoint()) { + if(_ndb_id == _kln89->GetActiveWaypoint()->id) { + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + // Active waypoint arrow + _kln89->DrawSpecialChar(4, 2, 0, 3); + } + } + } + if(_kln89->_mode != KLN89_MODE_CRSR) { + if(!_entInvert) { + if(!actPage) { + _kln89->DrawText(np->get_ident(), 2, 1, 3); + } else { + // If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index. + _kln89->DrawText(np->get_ident(), 2, 4, 3); + char buf[3]; + int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1); + _kln89->DrawText((string)buf, 2, 3 - n, 3); + } + } else { + if(!_kln89->_blink) { + _kln89->DrawText(np->get_ident(), 2, 1, 3, false, 99); + _kln89->DrawEnt(); + } + } + } + if(_subPage == 0) { + // TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc + _kln89->DrawText(np->get_name(), 2, 0, 2); + _kln89->DrawLatitude(np->get_lat(), 2, 3, 1); + _kln89->DrawLongitude(np->get_lon(), 2, 3, 0); + } else { + _kln89->DrawDirDistField(np->get_lat() * SG_DEGREES_TO_RADIANS, np->get_lon() * SG_DEGREES_TO_RADIANS, + 2, 0, 0, _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 4 ? true : false)); + } + } else { + if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_ndb_id, 2, 1, 3); + if(_subPage == 0) { + _kln89->DrawText("----.-", 2, 9, 3); + _kln89->DrawText("--------------", 2, 0, 2); + _kln89->DrawText("- -- --.--'", 2, 3, 1); + _kln89->DrawText("---- --.--'", 2, 3, 0); + _kln89->DrawSpecialChar(0, 2, 7, 1); + _kln89->DrawSpecialChar(0, 2, 7, 0); + } + } + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_uLinePos > 0 && _uLinePos < 4) { + // TODO - blink as well + _kln89->Underline(2, _uLinePos, 3, 1); + } + for(unsigned int i = 0; i < _ndb_id.size(); ++i) { + if(_uLinePos != (i + 1)) { + _kln89->DrawChar(_ndb_id[i], 2, i + 1, 3); + } else { + if(!_kln89->_blink) _kln89->DrawChar(_ndb_id[i], 2, i + 1, 3); + } + } + } + + _id = _ndb_id; + + KLN89Page::Update(dt); +} + +void KLN89NDBPage::SetId(string s) { + _last_ndb_id = _ndb_id; + _save_ndb_id = _ndb_id; + _ndb_id = s; + np = NULL; +} + +void KLN89NDBPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) return; + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + _uLinePos = 1; + } + if(_subPage == 0) { + _maxULinePos = 17; + } else { + _maxULinePos = 4; + } +} + +void KLN89NDBPage::ClrPressed() { + if(_subPage == 1 && _uLinePos == 4) { + _to_flag = !_to_flag; + } +} + +void KLN89NDBPage::EntPressed() { + if(_entInvert) { + _entInvert = false; + _last_ndb_id = _ndb_id; + _ndb_id = _save_ndb_id; + } +} + +void KLN89NDBPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Left1(); + } else { + if(_uLinePos < 4) { + // Same logic for both pages - set the ID + _ndb_id = _ndb_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_ndb_id.size() + 1)) { + _ndb_id += '9'; + } else { + _ndb_id[_uLinePos - 1] = _kln89->DecChar(_ndb_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // set by name + } else { + // NO-OP - from/to field is switched by clr button, not inner knob. + } + } + } +} + +void KLN89NDBPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Right1(); + } else { + if(_uLinePos < 4) { + // Same logic for both pages - set the ID + _ndb_id = _ndb_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_ndb_id.size() + 1)) { + _ndb_id += 'A'; + } else { + _ndb_id[_uLinePos - 1] = _kln89->IncChar(_ndb_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // set by name + } else { + // NO-OP - from/to field is switched by clr button, not inner knob. + } + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_ndb.hxx b/src/Instrumentation/KLN89/kln89_page_ndb.hxx new file mode 100644 index 000000000..373844dd8 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_ndb.hxx @@ -0,0 +1,52 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_NDB_HXX +#define _KLN89_PAGE_NDB_HXX + +#include "kln89.hxx" + +class KLN89NDBPage : public KLN89Page { + +public: + KLN89NDBPage(KLN89* parent); + ~KLN89NDBPage(); + + void Update(double dt); + + void CrsrPressed(); + void ClrPressed(); + void EntPressed(); + void Knob2Left1(); + void Knob2Right1(); + + void SetId(string s); + +private: + string _ndb_id; + string _last_ndb_id; + string _save_ndb_id; + FGNavRecord* np; +}; + +#endif // _KLN89_PAGE_NDB_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_nrst.cxx b/src/Instrumentation/KLN89/kln89_page_nrst.cxx new file mode 100644 index 000000000..fad2170ab --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_nrst.cxx @@ -0,0 +1,86 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_nrst.hxx" + +KLN89NrstPage::KLN89NrstPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 2; + _subPage = 0; + _name = "NRST"; + _uLinePos = 1; + _maxULinePos = 8; +} + +KLN89NrstPage::~KLN89NrstPage() { +} + +void KLN89NrstPage::Update(double dt) { + // crsr is always on on nearest page + bool blink = _kln89->_blink; + + _kln89->DrawText("NEAREST", 2, 3, 3); + if(!(_uLinePos == 1 && blink)) _kln89->DrawText("APT?", 2, 0, 2); + if(!(_uLinePos == 2 && blink)) _kln89->DrawText("VOR?", 2, 5, 2); + if(!(_uLinePos == 3 && blink)) _kln89->DrawText("NDB?", 2, 10, 2); + if(!(_uLinePos == 4 && blink)) _kln89->DrawText("INT?", 2, 0, 1); + if(!(_uLinePos == 5 && blink)) _kln89->DrawText("USR?", 2, 5, 1); + if(!(_uLinePos == 6 && blink)) _kln89->DrawText("SUA?", 2, 10, 1); + if(!(_uLinePos == 7 && blink)) _kln89->DrawText("FSS?", 2, 0, 0); + if(!(_uLinePos == 8 && blink)) _kln89->DrawText("CTR?", 2, 5, 0); + + switch(_uLinePos) { + case 1: _kln89->Underline(2, 0, 2, 4); break; + case 2: _kln89->Underline(2, 5, 2, 4); break; + case 3: _kln89->Underline(2, 10, 2, 4); break; + case 4: _kln89->Underline(2, 0, 1, 4); break; + case 5: _kln89->Underline(2, 5, 1, 4); break; + case 6: _kln89->Underline(2, 10, 1, 4); break; + case 7: _kln89->Underline(2, 0, 0, 4); break; + case 8: _kln89->Underline(2, 5, 0, 4); break; + } + + // Actually, the kln89 sim from Bendix-King dosn't draw the 'ENT' + // for 'APT?' if it was on 'Leg' (pos 0) immediately previously, but does if + // it was not on 'Leg' immediately previously. I think we can desist from + // reproducing this probable bug. + if(_uLinePos > 0) { + if(!blink) _kln89->DrawEnt(); + } + + KLN89Page::Update(dt); +} + +void KLN89NrstPage::CrsrPressed() { +} + +void KLN89NrstPage::EntPressed() { + if(_uLinePos > 4) { + ShowScratchpadMessage(" No ", " Nrst "); + } +} + +void KLN89NrstPage::LooseFocus() { + _uLinePos = 1; + _scratchpadMsg = false; +} diff --git a/src/Instrumentation/KLN89/kln89_page_nrst.hxx b/src/Instrumentation/KLN89/kln89_page_nrst.hxx new file mode 100644 index 000000000..1ad213c87 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_nrst.hxx @@ -0,0 +1,48 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_NRST +#define _KLN89_PAGE_NRST + +#include "kln89.hxx" + +class KLN89NrstPage : public KLN89Page { + +public: + KLN89NrstPage(KLN89* parent); + ~KLN89NrstPage(); + + void Update(double dt); + + void CrsrPressed(); + void EntPressed(); + //void ClrPressed(); + //void Knob1Left1(); + //void Knob1Right1(); + //void Knob2Left1(); + //void Knob2Right1(); + + void LooseFocus(); +}; + +#endif // _KLN89_PAGE_NRST diff --git a/src/Instrumentation/KLN89/kln89_page_oth.cxx b/src/Instrumentation/KLN89/kln89_page_oth.cxx new file mode 100644 index 000000000..ae7ce92d2 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_oth.cxx @@ -0,0 +1,58 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_oth.hxx" + +KLN89OthPage::KLN89OthPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 12; + _subPage = 0; + _name = "OTH"; +} + +KLN89OthPage::~KLN89OthPage() { +} + +void KLN89OthPage::Update(double dt) { + // The OTH pages aren't terribly important at the moment, since we don't simulate + // error and failure, but lets hardwire some representitive output anyway. + if(_subPage == 0) { + _kln89->DrawText("State", 2, 0, 3); + _kln89->DrawText("GPS Alt", 2, 0, 2); + _kln89->DrawText("Estimated Posn", 2, 0, 1); + _kln89->DrawText("Error", 2, 1, 0); + + // FIXME - hardwired value. + _kln89->DrawText("NAV D", 2, 9, 3); + // TODO - add error physics to FG GPS where the alt value comes from. + char buf[6]; + int n = snprintf(buf, 5, "%i", _kln89->_altUnits == GPS_ALT_UNITS_FT ? (int)_kln89->_alt : (int)(_kln89->_alt * SG_FEET_TO_METER)); + _kln89->DrawText((string)buf, 2, 13-n, 2); + _kln89->DrawText(_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m", 2, 13, 2); + // FIXME - hardwired values. + // Note that a 5th digit if required is left padded one further at position 7. + _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "0.02nm" : "0.03km", 2, 8, 0); + } + + KLN89Page::Update(dt); +} diff --git a/src/Instrumentation/KLN89/kln89_page_oth.hxx b/src/Instrumentation/KLN89/kln89_page_oth.hxx new file mode 100644 index 000000000..b648d75d2 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_oth.hxx @@ -0,0 +1,39 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_OTH +#define _KLN89_PAGE_OTH + +#include "kln89.hxx" + +class KLN89OthPage : public KLN89Page { + +public: + KLN89OthPage(KLN89* parent); + ~KLN89OthPage(); + + void Update(double dt); + +}; + +#endif // _KLN89_PAGE_OTH diff --git a/src/Instrumentation/KLN89/kln89_page_set.cxx b/src/Instrumentation/KLN89/kln89_page_set.cxx new file mode 100644 index 000000000..fc09e81ad --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_set.cxx @@ -0,0 +1,291 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_set.hxx" + +#include +using namespace std; + +KLN89SetPage::KLN89SetPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 11; + _subPage = 0; + _name = "SET"; +} + +KLN89SetPage::~KLN89SetPage() { +} + +void KLN89SetPage::Update(double dt) { + string sBaro, sAlt, sVel; + switch(_subPage+1) { + case 1: + _kln89->DrawText("INIT POS:", 2, 0, 3); + break; + case 2: + _kln89->DrawText("DATE", 2, 0, 3); + _kln89->DrawText("TIME", 2, 0, 2); + _kln89->DrawText("Cord", 2, 0, 1); + _kln89->DrawText("Mag Var:", 2, 0, 0); + break; + case 3: + _kln89->DrawText("Update DB on", 2, 1, 3); + _kln89->DrawText("ground only", 2, 1, 2); + _kln89->DrawText("Key", 2, 0, 1); + _kln89->DrawText("Update pub DB?", 2, 0, 0); + break; + case 4: + //cout << "_uLinePos = " << _uLinePos << '\n'; + _kln89->DrawText("TURN", 2, 5, 3); + _kln89->DrawText("ANTICIPATION", 2, 1, 2); + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) { + if(!_kln89->_blink) { + _kln89->DrawText((_kln89->GetTurnAnticipation() ? "ENABLED" : "DISABLED"), 2, 3, 1); + } + _kln89->Underline(2, 3, 1, 8); + } else { + _kln89->DrawText((_kln89->GetTurnAnticipation() ? "ENABLED" : "DISABLED"), 2, 3, 1); + } + break; + case 5: + _kln89->DrawText("Default First", 2, 0, 3); + _kln89->DrawText("Character of", 2, 1, 2); + _kln89->DrawText("Wpt identifier", 2, 0, 1); + _kln89->DrawText("Entry:", 2, 3, 0); + break; + case 6: + _kln89->DrawText("NEAREST APT", 2, 1, 3); + _kln89->DrawText("CRITERIA", 2, 3, 2); + _kln89->DrawText("Length:", 2, 0, 1); + _kln89->DrawText("Surface:", 2, 0, 0); + break; + case 7: + _kln89->DrawText("SUA ALERT", 2, 3, 3); + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) { + if(!_kln89->_blink) { + _kln89->DrawText((_kln89->GetSuaAlertEnabled() ? "ENABLED" : "DISABLED"), 2, 4, 2); + } + _kln89->Underline(2, 4, 2, 8); + } else { + _kln89->DrawText((_kln89->GetSuaAlertEnabled() ? "ENABLED" : "DISABLED"), 2, 4, 2); + } + if(_kln89->GetSuaAlertEnabled()) { + _kln89->DrawText("Buffer:", 2, 0, 1); + _kln89->DrawSpecialChar(5, 2, 7, 1); // +- sign. + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2) { + if(!_kln89->_blink) { + _kln89->DrawText("00300", 2, 8, 1); // TODO - fix this hardwiring!!!! + } + _kln89->Underline(2, 8, 1, 5); + } else { + _kln89->DrawText("00300", 2, 8, 1); // TODO - fix this hardwiring!!!! + } + _kln89->DrawText("ft", 2, 13, 1); // TODO - fix this hardwiring!!!! + } + break; + case 8: + _kln89->DrawText("SET UNITS:", 2, 3, 3); + _kln89->DrawText("Baro :", 2, 0, 2); + _kln89->DrawText("Alt-APT :", 2, 0, 1); + _kln89->DrawText("Dist-Vel:", 2, 0, 0); + switch(_kln89->_baroUnits) { + case GPS_PRES_UNITS_IN: + sBaro = "\""; + break; + case GPS_PRES_UNITS_MB: + sBaro = "mB"; + break; + case GPS_PRES_UNITS_HP: + sBaro = "hP"; + break; + } + if(_kln89->_altUnits == GPS_ALT_UNITS_FT) sAlt = "ft"; + else sAlt = "m"; + if(_kln89->_distUnits == GPS_DIST_UNITS_NM) sVel = "nm-kt"; + else sVel = "km-"; + + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) { + if(!_kln89->_blink) { + _kln89->DrawText(sBaro, 2, 10, 2); + } + _kln89->Underline(2, 10, 2, 2); + } else { + _kln89->DrawText(sBaro, 2, 10, 2); + } + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2) { + if(!_kln89->_blink) { + _kln89->DrawText(sAlt, 2, 10, 1); + } + _kln89->Underline(2, 10, 1, 2); + } else { + _kln89->DrawText(sAlt, 2, 10, 1); + } + if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3) { + if(!_kln89->_blink) { + _kln89->DrawText(sVel, 2, 10, 0); + if(_kln89->_distUnits != GPS_DIST_UNITS_NM) _kln89->DrawKPH(2, 13, 0); + } + _kln89->Underline(2, 10, 0, 5); + } else { + _kln89->DrawText(sVel, 2, 10, 0); + if(_kln89->_distUnits != GPS_DIST_UNITS_NM) _kln89->DrawKPH(2, 13, 0); + } + break; + case 9: + _kln89->DrawText("Altitude", 2, 3, 3); + _kln89->DrawText("Alert:", 2, 1, 2); + break; + case 10: + _kln89->DrawText("BUS MONITOR", 2, 2, 3); + _kln89->DrawText("Bus Volt", 2, 0, 2); + _kln89->DrawText("Alert Volt", 2, 0, 1); + _kln89->DrawText("Alert Delay", 2, 0, 0); + break; + case 11: + _kln89->DrawText("MIN DISPLAY", 2, 2, 3); + _kln89->DrawText("BRIGHTNESS ADJ", 2, 1, 2); + break; + } + + KLN89Page::Update(dt); +} + +void KLN89SetPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) return; + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + _uLinePos = 1; + } + switch(_subPage+1) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + _maxULinePos = 1; + break; + case 5: + break; + case 6: + _maxULinePos = 2; + break; + case 7: + if(_kln89->GetSuaAlertEnabled()) _maxULinePos = 2; + else _maxULinePos = 1; + break; + case 8: + _maxULinePos = 3; + break; + case 9: + break; + case 10: + break; + case 11: + break; + } +} + +void KLN89SetPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Left1(); + } else { + switch(_subPage+1) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + if(_uLinePos == 1) { + _kln89->SetTurnAnticipation(!_kln89->GetTurnAnticipation()); + } + break; + case 5: + break; + case 6: + break; + case 7: + if(_uLinePos == 1) { + _kln89->SetSuaAlertEnabled(!_kln89->GetSuaAlertEnabled()); + _maxULinePos = (_kln89->GetSuaAlertEnabled() ? 2 : 1); + } else if(_uLinePos == 2) { + // TODO - implement variable sua alert buffer + } + break; + case 8: + if(_uLinePos == 1) { // baro units + _kln89->SetBaroUnits(_kln89->GetBaroUnits() - 1, true); + } else if(_uLinePos == 2) { + _kln89->SetAltUnitsSI(!_kln89->GetAltUnitsSI()); + } else if(_uLinePos == 3) { + _kln89->SetDistVelUnitsSI(!_kln89->GetDistVelUnitsSI()); + } + break; + } + } +} + +void KLN89SetPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Right1(); + } else { + switch(_subPage+1) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + if(_uLinePos == 1) { // Which it should be! + _kln89->SetTurnAnticipation(!_kln89->GetTurnAnticipation()); + } + break; + case 5: + break; + case 6: + break; + case 7: + if(_uLinePos == 1) { + _kln89->SetSuaAlertEnabled(!_kln89->GetSuaAlertEnabled()); + _maxULinePos = (_kln89->GetSuaAlertEnabled() ? 2 : 1); + } else if(_uLinePos == 2) { + // TODO - implement variable sua alert buffer + } + break; + case 8: + if(_uLinePos == 1) { // baro units + _kln89->SetBaroUnits(_kln89->GetBaroUnits() + 1, true); + } else if(_uLinePos == 2) { + _kln89->SetAltUnitsSI(!_kln89->GetAltUnitsSI()); + } else if(_uLinePos == 3) { + _kln89->SetDistVelUnitsSI(!_kln89->GetDistVelUnitsSI()); + } + break; + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_set.hxx b/src/Instrumentation/KLN89/kln89_page_set.hxx new file mode 100644 index 000000000..3f2e77438 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_set.hxx @@ -0,0 +1,42 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_SET_HXX +#define _KLN89_PAGE_SET_HXX + +#include "kln89.hxx" + +class KLN89SetPage : public KLN89Page { + +public: + KLN89SetPage(KLN89* parent); + ~KLN89SetPage(); + + void Update(double dt); + + void CrsrPressed(); + void Knob2Left1(); + void Knob2Right1(); +}; + +#endif // _KLN89_PAGE_SET_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_usr.cxx b/src/Instrumentation/KLN89/kln89_page_usr.cxx new file mode 100644 index 000000000..bf2cdcefe --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_usr.cxx @@ -0,0 +1,51 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_usr.hxx" + +KLN89UsrPage::KLN89UsrPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 4; + _subPage = 0; + _name = "USR"; +} + +KLN89UsrPage::~KLN89UsrPage() { +} + +void KLN89UsrPage::Update(double dt) { + bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false); + bool crsr = (_kln89->_mode == KLN89_MODE_CRSR); + bool blink = _kln89->_blink; + + if(_subPage == 0) { + // Hardwire no-waypoint output for now + _kln89->DrawText("0", 2, 1, 3); + _kln89->DrawText("USR at:", 2, 7, 3); + if(!(crsr && _uLinePos == 6 && blink)) _kln89->DrawText("User Pos L/L?", 2, 1, 2); + if(!(crsr && _uLinePos == 7 && blink)) _kln89->DrawText("User Pos R/D?", 2, 1, 1); + if(!(crsr && _uLinePos == 8 && blink)) _kln89->DrawText("Present Pos?", 2, 1, 0); + } + + KLN89Page::Update(dt); +} diff --git a/src/Instrumentation/KLN89/kln89_page_usr.hxx b/src/Instrumentation/KLN89/kln89_page_usr.hxx new file mode 100644 index 000000000..dd8bbc387 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_usr.hxx @@ -0,0 +1,39 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_USR_HXX +#define _KLN89_PAGE_USR_HXX + +#include "kln89.hxx" + +class KLN89UsrPage : public KLN89Page { + +public: + KLN89UsrPage(KLN89* parent); + ~KLN89UsrPage(); + + void Update(double dt); + +}; + +#endif // _KLN89_PAGE_USR_HXX diff --git a/src/Instrumentation/KLN89/kln89_page_vor.cxx b/src/Instrumentation/KLN89/kln89_page_vor.cxx new file mode 100644 index 000000000..3456c6e80 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_vor.cxx @@ -0,0 +1,217 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#include "kln89_page_vor.hxx" + +KLN89VorPage::KLN89VorPage(KLN89* parent) +: KLN89Page(parent) { + _nSubPages = 2; + _subPage = 0; + _name = "VOR"; + _vor_id = "OSI"; // TODO - check a property for an initial value to allow user-override. + np = NULL; +} + +KLN89VorPage::~KLN89VorPage() { +} + +void KLN89VorPage::Update(double dt) { + bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false); + bool multi; // Not set by FindFirst... + bool exact = false; + if(_vor_id.size() == 3) exact = true; + if(np == NULL) { + np = _kln89->FindFirstVorById(_vor_id, multi, exact); + } else if(np->get_ident() != _vor_id) { + np = _kln89->FindFirstVorById(_vor_id, multi, exact); + } + //if(np == NULL) cout << "NULL... "; + //if(b == false) cout << "false...\n"; + /* + if(np && b) { + cout << "VOR FOUND!\n"; + } else { + cout << ":-(\n"; + } + */ + if(np) { + //cout << np->id << '\n'; + _vor_id = np->get_ident(); + if(_kln89->GetActiveWaypoint()) { + if(_vor_id == _kln89->GetActiveWaypoint()->id) { + if(!(_kln89->_waypointAlert && _kln89->_blink)) { + // Active waypoint arrow + _kln89->DrawSpecialChar(4, 2, 0, 3); + } + } + } + if(_kln89->_mode != KLN89_MODE_CRSR) { + if(!_entInvert) { + if(!actPage) { + _kln89->DrawText(np->get_ident(), 2, 1, 3); + } else { + // If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index. + _kln89->DrawText(np->get_ident(), 2, 4, 3); + char buf[3]; + int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1); + _kln89->DrawText((string)buf, 2, 3 - n, 3); + } + } else { + if(!_kln89->_blink) { + _kln89->DrawText(np->get_ident(), 2, 1, 3, false, 99); + _kln89->DrawEnt(); + } + } + } + if(_subPage == 0) { + //// TODO - will almost certainly have to process freq below for FG + _kln89->DrawFreq(np->get_freq(), 2, 9, 3); + // TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc + _kln89->DrawText(np->get_name(), 2, 0, 2); + //cout << np->lat << "... "; + _kln89->DrawLatitude(np->get_lat(), 2, 3, 1); + _kln89->DrawLongitude(np->get_lon(), 2, 3, 0); + } else { + _kln89->DrawText("Mag Var", 2, 0, 2); + ////float mvf = np->magvar * SG_RADIANS_TO_DEGREES; + //// TODO FIXME BELOW + float mvf = 0.0; + _kln89->DrawChar((mvf <= 0 ? 'E' : 'W'), 2, 9, 2); + int mvi = (int)(fabs(mvf) + 0.5); + string mvs = GPSitoa(mvi); + _kln89->DrawText(mvs, 2, 13 - mvs.size(), 2); + _kln89->DrawSpecialChar(0, 2, 13, 2); + _kln89->DrawDirDistField(np->get_lat() * SG_DEGREES_TO_RADIANS, np->get_lon() * SG_DEGREES_TO_RADIANS, 2, 0, 0, + _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 4 ? true : false)); + } + } else { + if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_vor_id, 2, 1, 3); + if(_subPage == 0) { + _kln89->DrawText("---.--", 2, 9, 3); + _kln89->DrawText("--------------", 2, 0, 2); + _kln89->DrawText("- -- --.--'", 2, 3, 1); + _kln89->DrawText("---- --.--'", 2, 3, 0); + _kln89->DrawSpecialChar(0, 2, 7, 1); + _kln89->DrawSpecialChar(0, 2, 7, 0); + } + } + + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_uLinePos > 0 && _uLinePos < 4) { + // TODO - blink as well + _kln89->Underline(2, _uLinePos, 3, 1); + } + for(unsigned int i = 0; i < _vor_id.size(); ++i) { + if(_uLinePos != (i + 1)) { + _kln89->DrawChar(_vor_id[i], 2, i + 1, 3); + } else { + if(!_kln89->_blink) _kln89->DrawChar(_vor_id[i], 2, i + 1, 3); + } + } + } + + _id = _vor_id; + + KLN89Page::Update(dt); +} + +void KLN89VorPage::SetId(string s) { + _last_vor_id = _vor_id; + _save_vor_id = _vor_id; + _vor_id = s; + np = NULL; +} + +void KLN89VorPage::CrsrPressed() { + if(_kln89->_mode == KLN89_MODE_DISP) return; + if(_kln89->_obsMode) { + _uLinePos = 0; + } else { + _uLinePos = 1; + } + if(_subPage == 0) { + _maxULinePos = 17; + } else { + _maxULinePos = 4; + } +} + +void KLN89VorPage::ClrPressed() { + if(_subPage == 1 && _uLinePos == 4) { + _to_flag = !_to_flag; + } +} + +void KLN89VorPage::EntPressed() { + if(_entInvert) { + _entInvert = false; + _last_vor_id = _vor_id; + _vor_id = _save_vor_id; + } +} + +void KLN89VorPage::Knob2Left1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Left1(); + } else { + if(_uLinePos < 4) { + // Same logic for both pages - set the ID + _vor_id = _vor_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_vor_id.size() + 1)) { + _vor_id += '9'; + } else { + _vor_id[_uLinePos - 1] = _kln89->DecChar(_vor_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // set by name + } else { + // NO-OP - from/to field is switched by clr button, not inner knob. + } + } + } +} + +void KLN89VorPage::Knob2Right1() { + if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) { + KLN89Page::Knob2Right1(); + } else { + if(_uLinePos < 4) { + // Same logic for both pages - set the ID + _vor_id = _vor_id.substr(0, _uLinePos); + // ASSERT(_uLinePos > 0); + if(_uLinePos == (_vor_id.size() + 1)) { + _vor_id += 'A'; + } else { + _vor_id[_uLinePos - 1] = _kln89->IncChar(_vor_id[_uLinePos - 1], (_uLinePos == 1 ? false : true)); + } + } else { + if(_subPage == 0) { + // set by name + } else { + // NO-OP - from/to field is switched by clr button, not inner knob. + } + } + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_vor.hxx b/src/Instrumentation/KLN89/kln89_page_vor.hxx new file mode 100644 index 000000000..a9fc412f2 --- /dev/null +++ b/src/Instrumentation/KLN89/kln89_page_vor.hxx @@ -0,0 +1,52 @@ +// kln89_page_*.[ch]xx - this file is one of the "pages" that +// are used in the KLN89 GPS unit simulation. +// +// Written by David Luff, started 2005. +// +// Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifndef _KLN89_PAGE_VOR_HXX +#define _KLN89_PAGE_VOR_HXX + +#include "kln89.hxx" + +class KLN89VorPage : public KLN89Page { + +public: + KLN89VorPage(KLN89* parent); + ~KLN89VorPage(); + + void Update(double dt); + + void CrsrPressed(); + void ClrPressed(); + void EntPressed(); + void Knob2Left1(); + void Knob2Right1(); + + void SetId(string s); + +private: + string _vor_id; + string _last_vor_id; + string _save_vor_id; + FGNavRecord* np; +}; + +#endif // _KLN89_PAGE_VOR_HXX -- 2.39.5