From 8de8a734a26b60a6c6ace3e4b9230d1672ebb283 Mon Sep 17 00:00:00 2001 From: daveluff Date: Sat, 17 Oct 2009 11:43:19 +0000 Subject: [PATCH 01/10] Fix a crash where there is only 1 IAF in an approach --- src/Instrumentation/KLN89/kln89_page_apt.cxx | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index c17dbff12..e2f7597e4 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -731,6 +731,30 @@ void KLN89AptPage::EntPressed() { _iafDialog = true; _maxULinePos = _IAF.size(); } else { + // There is only 1 IAF, so load the waypoints into the approach flightplan here. + // TODO - there is nasty code duplication loading the approach FP between the case here where we have only one + // IAF and the case where we must choose the IAF from a list. Try to tidy this after it is all working properly. + _kln89->_approachFP->waypoints.clear(); + GPSWaypoint* wp = new GPSWaypoint; + *wp = *_IAF[0]; // Need to make copies here since we're going to alter ID and type sometimes + string iafid = wp->id; + _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]; + _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); + _addDialog = true; _maxULinePos = 1; } From a01bee38179b255a60b438211ee1e64ffef7e3da Mon Sep 17 00:00:00 2001 From: daveluff Date: Sat, 17 Oct 2009 11:48:17 +0000 Subject: [PATCH 02/10] Change one of the default flight plans to something more convenient for development. These will eventually all be removed from the code and read from preferences anyway. --- src/Instrumentation/KLN89/kln89.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89.cxx b/src/Instrumentation/KLN89/kln89.cxx index da1134bea..4387ddc19 100644 --- a/src/Instrumentation/KLN89/kln89.cxx +++ b/src/Instrumentation/KLN89/kln89.cxx @@ -365,11 +365,7 @@ void KLN89::CreateDefaultFlightPlans() { wps.clear(); ids.push_back("KCCR"); wps.push_back(GPS_WP_APT); - ids.push_back("SUZYE"); - wps.push_back(GPS_WP_INT); - ids.push_back("ALTAM"); - wps.push_back(GPS_WP_INT); - ids.push_back("C83"); + ids.push_back("KHAF"); wps.push_back(GPS_WP_APT); CreateFlightPlan(_flightPlans[4], ids, wps); From 882f5b4deb5c256d48e0ef0047bf224242eda3d7 Mon Sep 17 00:00:00 2001 From: daveluff Date: Sat, 17 Oct 2009 13:04:21 +0000 Subject: [PATCH 03/10] My non-precision approach model had been one or more IAFs and then a common core approach from the IF. In fact, there can be one or more initial approach routes from the IAFs to the IF, then the core approach. Replace the IAFs with initial approach routes. NOTE it is assumed in the code that there is a unique IAF per initial approach route. --- src/Instrumentation/KLN89/kln89_page_apt.cxx | 24 ++++++++++---------- src/Instrumentation/KLN89/kln89_page_apt.hxx | 4 ++-- src/Instrumentation/dclgps.hxx | 3 ++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index e2f7597e4..a4ed0a6dc 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -358,14 +358,14 @@ void KLN89AptPage::Update(double dt) { _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); _kln89->DrawText("IAF", 2, 2, 2); unsigned int line = 0; - for(unsigned int i=_iafStart; i<_IAF.size(); ++i) { + for(unsigned int i=_iafStart; i<_approachRoutes.size(); ++i) { if(line == 2) { - i = _IAF.size() - 1; + i = _approachRoutes.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); + _kln89->DrawText(_approachRoutes[i]->waypoints[0]->id, 2, 8, 2-line); } if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (line + 1) && !(_kln89->_blink )) { _kln89->Underline(2, 8, 2-line, 5); @@ -571,7 +571,7 @@ void KLN89AptPage::CrsrPressed() { } 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(); + _maxULinePos = _approachRoutes.size(); _uLinePos = 1; } else if(_addDialog) { _maxULinePos = 1; @@ -607,7 +607,7 @@ void KLN89AptPage::ClrPressed() { } } else if(_addDialog) { _addDialog = false; - if(_IAF.size() > 1) { + if(_approachRoutes.size() > 1) { _iafDialog = true; _maxULinePos = 1; // Don't reset _curIaf since it is remembed. @@ -640,7 +640,7 @@ void KLN89AptPage::EntPressed() { if(_uLinePos > 0) { // Record the IAF that was picked if(_uLinePos == 3) { - _curIaf = _IAF.size() - 1; + _curIaf = _approachRoutes.size() - 1; } else { _curIaf = _uLinePos - 1 + _iafStart; } @@ -648,7 +648,7 @@ void KLN89AptPage::EntPressed() { // 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 + *wp = *(_approachRoutes[_curIaf]->waypoints[0]); // 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); @@ -717,26 +717,26 @@ void KLN89AptPage::EntPressed() { } else if(_replaceDialog) { // TODO - load the approach! } else if(_uLinePos > 4) { - _IAF.clear(); + _approachRoutes.clear(); _IAP.clear(); _MAP.clear(); _curIaf = 0; - _IAF = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_IAF; + _approachRoutes = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_approachRoutes; _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) { + if(_approachRoutes.size() > 1) { // More than 1 IAF - display the selection dialog _iafDialog = true; - _maxULinePos = _IAF.size(); + _maxULinePos = _approachRoutes.size(); } else { // There is only 1 IAF, so load the waypoints into the approach flightplan here. // TODO - there is nasty code duplication loading the approach FP between the case here where we have only one // IAF and the case where we must choose the IAF from a list. Try to tidy this after it is all working properly. _kln89->_approachFP->waypoints.clear(); GPSWaypoint* wp = new GPSWaypoint; - *wp = *_IAF[0]; // Need to make copies here since we're going to alter ID and type sometimes + *wp = *(_approachRoutes[0]->waypoints[0]); // Need to make copies here since we're going to alter ID and type sometimes string iafid = wp->id; _kln89->_approachFP->waypoints.push_back(wp); for(unsigned int i=0; i<_IAP.size(); ++i) { diff --git a/src/Instrumentation/KLN89/kln89_page_apt.hxx b/src/Instrumentation/KLN89/kln89_page_apt.hxx index 33dd5603c..993fca550 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.hxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.hxx @@ -65,11 +65,11 @@ private: 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 _approachRoutes; // The approach route(s) from the IAF(s) to the IF. 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 + unsigned int _curIaf; // The index into _approachRoutes of the IAF we are currently selecting, and then remembered as the one we selected // Position in rwy pages unsigned int _curRwyPage; diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index 2f0d0f6e3..4c0b1a6fa 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -140,7 +140,8 @@ public: ~FGNPIAP(); //private: public: - vector _IAF; // The initial approach fix(es) + vector _approachRoutes; // The approach route(s) from the IAF(s) to the IF. + // NOTE: It is an assumption in the code that uses this that there is a unique IAF per approach route. 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). From a2401ea94b61989238eac9bfe38ed86817cbf2ff Mon Sep 17 00:00:00 2001 From: daveluff Date: Sun, 18 Oct 2009 00:32:47 +0000 Subject: [PATCH 04/10] Add a hardwired instrument approach for testing. This will be removed and read from file shortly --- src/Instrumentation/dclgps.cxx | 92 ++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index af232d70b..da43c4970 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -238,6 +239,97 @@ void DCLGPS::init() { // Not sure if this should be here, but OK for now. CreateDefaultFlightPlans(); + + // Hack - hardwire some instrument approaches for development. + // These will shortly be replaced by a routine to read ARINC data from file instead. + FGNPIAP* iap; + GPSWaypoint* wp; + GPSFlightPlan* fp; + const GPSWaypoint* cwp; + + iap = new FGNPIAP; + iap->_id = "KHAF"; + iap->_name = "RNAV (GPS) Y RWY 12"; + iap->_abbrev = "R12-Y"; + iap->_rwyStr = "12"; + iap->_approachRoutes.clear(); + iap->_IAP.clear(); + iap->_MAP.clear(); + // ------- + wp = new GPSWaypoint; + wp->id = "GOBBS"; + // Nasty using the find any function here, but it saves converting data from FGFix etc. + cwp = FindFirstByExactId(wp->id); + if(cwp) { + *wp = *cwp; + wp->appType = GPS_IAF; + fp = new GPSFlightPlan; + fp->waypoints.push_back(wp); + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + // ------- + wp = new GPSWaypoint; + wp->id = "FUJCE"; + cwp = FindFirstByExactId(wp->id); + if(cwp) { + *wp = *cwp; + wp->appType = GPS_IAP; + fp->waypoints.push_back(wp); + iap->_approachRoutes.push_back(fp); + iap->_IAP.push_back(wp); + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + // ------- + wp = new GPSWaypoint; + wp->id = "JEVXY"; + cwp = FindFirstByExactId(wp->id); + if(cwp) { + *wp = *cwp; + wp->appType = GPS_FAF; + iap->_IAP.push_back(wp); + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + // ------- + wp = new GPSWaypoint; + wp->id = "RW12"; + wp->appType = GPS_MAP; + if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) { + // Assume that this is a missed-approach point based on the runway number, which appears to be standard for most approaches. + const FGAirport* apt = fgFindAirportID(iap->_id); + if(apt) { + // TODO - sanity check the waypoint ID to ensure we have a double digit number + FGRunway* rwy = apt->getRunwayByIdent(wp->id.substr(2, 2)); + if(rwy) { + wp->lat = rwy->begin().getLatitudeRad(); + wp->lon = rwy->begin().getLongitudeRad(); + } + } + } else { + cwp = FindFirstByExactId(wp->id); + if(cwp) { + *wp = *cwp; + wp->appType = GPS_MAP; + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + } + iap->_IAP.push_back(wp); + // ------- + wp = new GPSWaypoint; + wp->id = "SEEMS"; + cwp = FindFirstByExactId(wp->id); + if(cwp) { + *wp = *cwp; + wp->appType = GPS_MAHP; + iap->_MAP.push_back(wp); + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + // ------- + _np_iap[iap->_id].push_back(iap); } void DCLGPS::bind() { From 0112b2454094b9f8147e2b8c87e9093e017c50f3 Mon Sep 17 00:00:00 2001 From: daveluff Date: Sat, 24 Oct 2009 19:36:12 +0000 Subject: [PATCH 05/10] Expand SIAP idents as found in FAA ARINC dataset to the full approach name as shown on the approach chart and possibly the GPS --- src/Instrumentation/KLN89/kln89_page_apt.cxx | 16 ++-- src/Instrumentation/dclgps.cxx | 83 ++++++++++++++++++-- src/Instrumentation/dclgps.hxx | 9 ++- 3 files changed, 92 insertions(+), 16 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index a4ed0a6dc..db4a8c115 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -353,9 +353,9 @@ void KLN89AptPage::Update(double dt) { _kln89->DrawText("For This Airport", 2, 0, 0); } else { if(_iafDialog) { - _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3); _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); - _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + _kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3); _kln89->DrawText("IAF", 2, 2, 2); unsigned int line = 0; for(unsigned int i=_iafStart; i<_approachRoutes.size(); ++i) { @@ -376,9 +376,9 @@ void KLN89AptPage::Update(double dt) { _kln89->DrawEnt(); } } else if(_addDialog) { - _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3); _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); - _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + _kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3); string s = GPSitoa(_fStart + 1); _kln89->DrawText(s, 2, 2-s.size(), 2); s = GPSitoa(_kln89->_approachFP->waypoints.size()); @@ -399,9 +399,9 @@ void KLN89AptPage::Update(double dt) { } } } else if(_replaceDialog) { - _kln89->DrawText(_iaps[_curIap]->_abbrev, 2, 1, 3); + _kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3); _kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3); - _kln89->DrawText(_iaps[_curIap]->_id, 2, 12, 3); + _kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3); _kln89->DrawText("Replace Existing", 2, 0, 2); _kln89->DrawText("Approach", 2, 4, 1); if(_uLinePos > 0 && !(_kln89->_blink)) { @@ -421,7 +421,7 @@ void KLN89AptPage::Update(double dt) { 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]->_ident, 2, 3, 2-i); _kln89->DrawText(_iaps[i]->_rwyStr, 2, 9, 2-i); } if(selApp && _uLinePos == 5+i && !_kln89->_blink) { @@ -702,7 +702,7 @@ void KLN89AptPage::EntPressed() { _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->_approachAbbrev = _iaps[_curIap]->_ident; _kln89->_approachRwyStr = _iaps[_curIap]->_rwyStr; _kln89->_approachLoaded = true; //_kln89->_messageStack.push_back("*Press ALT To Set Baro"); diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index da43c4970..4a2ccabf3 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -248,9 +248,9 @@ void DCLGPS::init() { const GPSWaypoint* cwp; iap = new FGNPIAP; - iap->_id = "KHAF"; - iap->_name = "RNAV (GPS) Y RWY 12"; - iap->_abbrev = "R12-Y"; + iap->_aptIdent = "KHAF"; + iap->_ident = "R12-Y"; + iap->_name = ExpandSIAPIdent(iap->_ident); iap->_rwyStr = "12"; iap->_approachRoutes.clear(); iap->_IAP.clear(); @@ -298,7 +298,7 @@ void DCLGPS::init() { wp->appType = GPS_MAP; if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) { // Assume that this is a missed-approach point based on the runway number, which appears to be standard for most approaches. - const FGAirport* apt = fgFindAirportID(iap->_id); + const FGAirport* apt = fgFindAirportID(iap->_aptIdent); if(apt) { // TODO - sanity check the waypoint ID to ensure we have a double digit number FGRunway* rwy = apt->getRunwayByIdent(wp->id.substr(2, 2)); @@ -329,7 +329,7 @@ void DCLGPS::init() { //cout << "Unable to find waypoint " << wp->id << '\n'; } // ------- - _np_iap[iap->_id].push_back(iap); + _np_iap[iap->_aptIdent].push_back(iap); } void DCLGPS::bind() { @@ -613,6 +613,79 @@ void DCLGPS::update(double dt) { } } +/* + Expand a SIAP ident to the full procedure name (as shown on the approach chart). + NOTE: Some of this is inferred from data, some is from documentation. + + Example expansions from ARINC 424-18 [and the airport they're taken from]: + "R10LY" <--> "RNAV (GPS) Y RWY 10 L" [KBOI] + "R10-Z" <--> "RNAV (GPS) Z RWY 10" [KHTO] + "S25" <--> "VOR or GPS RWY 25" [KHHR] + "P20" <--> "GPS RWY 20" [KDAN] + "NDB-B" <--> "NDB or GPS-B" [KDAW] + "NDBC" <--> "NDB or GPS-C" [KEMT] + "VDMA" <--> "VOR/DME or GPS-A" [KDAW] + "VDM-A" <--> "VOR/DME or GPS-A" [KEAG] + "VDMB" <--> "VOR/DME or GPS-B" [KDKX] + "VORA" <--> "VOR or GPS-A" [KEMT] + + It seems that there are 2 basic types of expansions; those that include + the runway and those that don't. Of those that don't, it seems that 2 + different positions within the string to encode the identifying letter + are used, i.e. with a dash and without. +*/ +string DCLGPS::ExpandSIAPIdent(const string& ident) { + string name; + bool has_rwy; + + switch(ident[0]) { + case 'N': name = "NDB or GPS"; has_rwy = false; break; + case 'P': name = "GPS"; has_rwy = true; break; + case 'R': name = "RNAV (GPS)"; has_rwy = true; break; + case 'S': name = "VOR or GPS"; has_rwy = true; break; + case 'V': + if(ident[1] == 'D') name = "VOR/DME or GPS"; + else name = "VOR or GPS"; + has_rwy = false; + break; + default: // TODO output a log message + break; + } + + if(has_rwy) { + // Add the identifying letter if present + if(ident.size() == 5) { + name += ' '; + name += ident[4]; + } + + // Add the runway + name += " RWY "; + name += ident.substr(1, 2); + + // Add a left/right/centre indication if present. + if(ident.size() > 3) { + if((ident[3] != '-') && (ident[3] != ' ')) { // Early versions of the spec allowed a blank instead of a dash so check for both + name += ' '; + name += ident[3]; + } + } + } else { + // Add the identifying letter, which I *think* should always be present, but seems to be inconsistent as to whether a dash is used. + if(ident.size() == 5) { + name += '-'; + name += ident[4]; + } else if(ident.size() == 4) { + name += '-'; + name += ident[3]; + } else { + // No suffix letter + } + } + + return(name); +} + GPSWaypoint* DCLGPS::GetActiveWaypoint() { return &_activeWaypoint; } diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index 4c0b1a6fa..9594304e6 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -126,9 +126,9 @@ public: virtual ~FGIAP() = 0; //protected: - string _id; // The ID of the airport this approach is for - string _name; // The approach name, eg "VOR/DME OR GPS-B" - string _abbrev; // The abbreviation the GPS unit uses - eg "VOR/D" in this instance. Possibly GPS model specific. + string _aptIdent; // The ident of the airport this approach is for + string _ident; // The approach ident. + string _name; // The full approach name. string _rwyStr; // The string used to specify the rwy - eg "B" in this instance. bool _precision; // True for precision approach, false for non-precision. }; @@ -200,6 +200,9 @@ public: virtual void bind(); virtual void unbind(); virtual void update(double dt); + + // Expand a SIAP ident to the full procedure name. + string ExpandSIAPIdent(const string& ident); // Render string s in display field field at position x, y // WHERE POSITION IS IN CHARACTER UNITS! From f696c541bec7190769d578926be7d3bd917ccb4b Mon Sep 17 00:00:00 2001 From: daveluff Date: Tue, 27 Oct 2009 00:32:57 +0000 Subject: [PATCH 06/10] Remove the unecessary distinction between waypoints of the core approach and waypoints of the missed approach procedure --- src/Instrumentation/KLN89/kln89_page_apt.cxx | 14 -------------- src/Instrumentation/dclgps.cxx | 3 +-- src/Instrumentation/dclgps.hxx | 3 +-- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index db4a8c115..83f0bc3b0 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -650,7 +650,6 @@ void KLN89AptPage::EntPressed() { GPSWaypoint* wp = new GPSWaypoint; *wp = *(_approachRoutes[_curIaf]->waypoints[0]); // 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. @@ -666,11 +665,6 @@ void KLN89AptPage::EntPressed() { _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; @@ -719,11 +713,9 @@ void KLN89AptPage::EntPressed() { } else if(_uLinePos > 4) { _approachRoutes.clear(); _IAP.clear(); - _MAP.clear(); _curIaf = 0; _approachRoutes = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_approachRoutes; _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(_approachRoutes.size() > 1) { @@ -749,12 +741,6 @@ void KLN89AptPage::EntPressed() { _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); - _addDialog = true; _maxULinePos = 1; } diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index 4a2ccabf3..6feb0a286 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -254,7 +254,6 @@ void DCLGPS::init() { iap->_rwyStr = "12"; iap->_approachRoutes.clear(); iap->_IAP.clear(); - iap->_MAP.clear(); // ------- wp = new GPSWaypoint; wp->id = "GOBBS"; @@ -324,7 +323,7 @@ void DCLGPS::init() { if(cwp) { *wp = *cwp; wp->appType = GPS_MAHP; - iap->_MAP.push_back(wp); + iap->_IAP.push_back(wp); } else { //cout << "Unable to find waypoint " << wp->id << '\n'; } diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index 9594304e6..76dd764dd 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -143,8 +143,7 @@ public: vector _approachRoutes; // The approach route(s) from the IAF(s) to the IF. // NOTE: It is an assumption in the code that uses this that there is a unique IAF per approach route. 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). + // _IAP includes the FAF and MAF, and the missed approach waypoints. }; typedef vector < FGIAP* > iap_list_type; From 00d9abef423c50e53076665c94efc530aafddeb0 Mon Sep 17 00:00:00 2001 From: daveluff Date: Tue, 3 Nov 2009 22:54:05 +0000 Subject: [PATCH 07/10] Make the comments about switching to the DIR page more useful --- src/Instrumentation/KLN89/kln89.cxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89.cxx b/src/Instrumentation/KLN89/kln89.cxx index 4387ddc19..eebf46e16 100644 --- a/src/Instrumentation/KLN89/kln89.cxx +++ b/src/Instrumentation/KLN89/kln89.cxx @@ -523,9 +523,15 @@ void KLN89::ClrPressed() { void KLN89::DtoPressed() { if(_activePage != _dir_page) { - // Figure out which waypoint the dir page should display + // Figure out which waypoint the dir page should display, according to the following rules: + // 1. If the FPL 0 page is displayed AND the cursor is over one of the waypoints, display that waypoint. + // 2. If the NAV 4 page is displayed with the inner knob pulled out, display the waypoint highlighted in the lower RH corner of the nav page. + // 3. If any of APT, VOR, NDB, INT, USR or ACT pages is displayed then display the waypoint being viewed. + // 4. If none of the above, display the active waypoint, unless the active waypoint is the MAP of an approach and it has been flown past + // (no waypoint sequence past the MAP), in which case display the first waypoint of the missed approach procedure. + // 5. If none of the above (i.e. no active waypoint) then display blanks. if(_curPage <= 5) { - // Apt, Vor, Ndb, Int, Usr or Act + // APT, VOR, NDB, INT, USR or ACT if(!_activePage->GetId().empty()) { // Guard against no user waypoints defined _dir_page->SetId(_activePage->GetId()); } else { @@ -535,7 +541,6 @@ void KLN89::DtoPressed() { // NAV 4 _dir_page->SetId(((KLN89NavPage*)_activePage)->GetNav4WpId()); } else if(_curPage == 7 && _activePage->GetSubPage() == 0 && _mode == KLN89_MODE_CRSR) { - //cout << "Checking the fpl page!\n"; // FPL 0 if(!_activePage->GetId().empty()) { //cout << "Not empty!!!\n"; From 24b57ada097653135f43e1d388bc05b8d08a7a6e Mon Sep 17 00:00:00 2001 From: daveluff Date: Tue, 3 Nov 2009 22:55:36 +0000 Subject: [PATCH 08/10] Allow the DIR page to be exited properly using the inner knob --- src/Instrumentation/KLN89/kln89_page_dir.cxx | 34 ++++++++++++++++++++ src/Instrumentation/KLN89/kln89_page_dir.hxx | 2 ++ 2 files changed, 36 insertions(+) diff --git a/src/Instrumentation/KLN89/kln89_page_dir.cxx b/src/Instrumentation/KLN89/kln89_page_dir.cxx index de761232a..c80bd2397 100644 --- a/src/Instrumentation/KLN89/kln89_page_dir.cxx +++ b/src/Instrumentation/KLN89/kln89_page_dir.cxx @@ -105,3 +105,37 @@ void KLN89DirPage::EntPressed() { _kln89->DtoInitiate(_id); } } + +void KLN89DirPage::Knob2Left1() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_DToWpDispMode == 0) { + _DToWpDispMode = 1; + } else if(_DToWpDispMode == 1) { + // TODO + } else { + // TODO + } + } else { + // If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed, + // and pass the knob turn to that page, whether pulled out or not. + _kln89->_activePage = _kln89->_pages[_kln89->_curPage]; + _kln89->_activePage->Knob2Left1(); + } +} + +void KLN89DirPage::Knob2Right1() { + if(_kln89->_mode == KLN89_MODE_CRSR) { + if(_DToWpDispMode == 0) { + _DToWpDispMode = 1; + } else if(_DToWpDispMode == 1) { + // TODO + } else { + // TODO + } + } else { + // If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed, + // and pass the knob turn to that page, whether pulled out or not. + _kln89->_activePage = _kln89->_pages[_kln89->_curPage]; + _kln89->_activePage->Knob2Right1(); + } +} diff --git a/src/Instrumentation/KLN89/kln89_page_dir.hxx b/src/Instrumentation/KLN89/kln89_page_dir.hxx index d9f66b691..fe8f18261 100644 --- a/src/Instrumentation/KLN89/kln89_page_dir.hxx +++ b/src/Instrumentation/KLN89/kln89_page_dir.hxx @@ -38,6 +38,8 @@ public: void ClrPressed(); void EntPressed(); + void Knob2Left1(); + void Knob2Right1(); private: // Waypoint display mode. From eb382545c5c1f7082c332af7b95073aa846310f5 Mon Sep 17 00:00:00 2001 From: daveluff Date: Thu, 5 Nov 2009 20:27:56 +0000 Subject: [PATCH 09/10] Allow all approaches to be selected at airports with more than 3 approaches --- src/Instrumentation/KLN89/kln89_page_apt.cxx | 53 +++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index 83f0bc3b0..1f4ffcb8a 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -411,24 +411,35 @@ void KLN89AptPage::Update(double dt) { } } 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]->_ident, 2, 3, 2-i); - _kln89->DrawText(_iaps[i]->_rwyStr, 2, 9, 2-i); + // _maxULine pos should be 4 + iaps.size() at this point. + // Draw a maximum of 3 IAPs. + // If there are more than 3 IAPs for this airport, then we need to offset the start + // of the list if _uLinePos is pointing at the 4th or later IAP. + unsigned int offset = 0; + unsigned int index; + if(_uLinePos > 7) { + offset = _uLinePos - 7; + } + for(unsigned int i=0; i<3; ++i) { + index = offset + i; + if(index < _iaps.size()) { + string s = GPSitoa(index+1); + _kln89->DrawText(s, 2, 2 - s.size(), 2-i); + if(!(selApp && _uLinePos == index+5 && _kln89->_blink)) { + _kln89->DrawText(_iaps[index]->_ident, 2, 3, 2-i); + _kln89->DrawText(_iaps[index]->_rwyStr, 2, 9, 2-i); + } + if(selApp && _uLinePos == index+5 && !_kln89->_blink) { + _kln89->Underline(2, 3, 2-i, 9); + } + } else { + break; } - if(selApp && _uLinePos == 5+i && !_kln89->_blink) { - _kln89->Underline(2, 3, 2-i, 9); - } - check++; - if(check > 2) break; } } } @@ -812,6 +823,15 @@ void KLN89AptPage::Knob2Left1() { } else { _curRwyPage--; } + } else if(_subPage == 0) { + _subPage = 7; + // We have to set _uLinePos here even though the cursor isn't pressed, to + // ensure that the list displays properly. + if(_iaps.empty()) { + _uLinePos = 1; + } else { + _uLinePos = 5; + } } else { KLN89Page::Knob2Left1(); } @@ -855,6 +875,15 @@ void KLN89AptPage::Knob2Right1() { } else { _curFreqPage++; } + } else if(_subPage == 6) { + _subPage = 7; + // We have to set _uLinePos here even though the cursor isn't pressed, to + // ensure that the list displays properly. + if(_iaps.empty()) { + _uLinePos = 1; + } else { + _uLinePos = 5; + } } else { KLN89Page::Knob2Right1(); } From e1af876a657784c298e118d0dfdbb48983d2f5b9 Mon Sep 17 00:00:00 2001 From: daveluff Date: Sat, 7 Nov 2009 00:18:08 +0000 Subject: [PATCH 10/10] Enable correct DTO waypoint selection --- src/Instrumentation/KLN89/kln89.cxx | 13 ++ src/Instrumentation/KLN89/kln89.hxx | 7 + src/Instrumentation/KLN89/kln89_page.cxx | 6 + src/Instrumentation/KLN89/kln89_page.hxx | 1 + src/Instrumentation/KLN89/kln89_page_apt.cxx | 8 +- src/Instrumentation/KLN89/kln89_page_dir.cxx | 207 +++++++++++++++++-- src/Instrumentation/KLN89/kln89_page_dir.hxx | 5 + src/Instrumentation/KLN89/kln89_page_int.cxx | 9 +- src/Instrumentation/KLN89/kln89_page_ndb.cxx | 8 +- src/Instrumentation/KLN89/kln89_page_vor.cxx | 9 +- src/Instrumentation/dclgps.cxx | 16 +- src/Instrumentation/dclgps.hxx | 10 +- 12 files changed, 261 insertions(+), 38 deletions(-) diff --git a/src/Instrumentation/KLN89/kln89.cxx b/src/Instrumentation/KLN89/kln89.cxx index eebf46e16..c028e17ae 100644 --- a/src/Instrumentation/KLN89/kln89.cxx +++ b/src/Instrumentation/KLN89/kln89.cxx @@ -206,6 +206,8 @@ KLN89::KLN89(RenderArea2D* instrument) _entRestoreCrsr = false; _dispMsg = false; + + _dtoReview = false; // Moving map stuff _mapOrientation = 0; @@ -597,6 +599,17 @@ void KLN89::ToggleOBSMode() { DCLGPS::ToggleOBSMode(); } +void KLN89::DtoInitiate(const string& id) { + _dtoReview = false; + // Set the current page to NAV1 + _curPage = 6; + _activePage = _pages[_curPage]; + _activePage->SetSubPage(0); + // TODO - need to output a scratchpad message with the new course, but we don't know it yet! + // Call the base class to actually initiate the DTO. + DCLGPS::DtoInitiate(id); +} + void KLN89::DrawBar(int page) { int px = 1 + (page * 15); int py = 1; diff --git a/src/Instrumentation/KLN89/kln89.hxx b/src/Instrumentation/KLN89/kln89.hxx index 26dcccd3d..2206fb1b0 100644 --- a/src/Instrumentation/KLN89/kln89.hxx +++ b/src/Instrumentation/KLN89/kln89.hxx @@ -107,6 +107,9 @@ public: private: void ToggleOBSMode(); + + // Initiate Direct To operation to the supplied ID. + void DtoInitiate(const string& id); //----------------------- Drawing functions which take CHARACTER units ------------------------- // Render string s in display field field at position x, y @@ -282,6 +285,10 @@ private: // since button events get directed to the page that was active before the // message was displayed, not the message page itself. bool _dispMsg; // Set true while the message page is being displayed + + // Sometimes the datapages can be used to review a waypoint whilst the user makes a decision, + // and we need to remember why. + bool _dtoReview; // Set true when we a reviewing a waypoint for DTO operation. }; #endif // _KLN89_HXX diff --git a/src/Instrumentation/KLN89/kln89_page.cxx b/src/Instrumentation/KLN89/kln89_page.cxx index d3e5b8d4b..43c78550b 100644 --- a/src/Instrumentation/KLN89/kln89_page.cxx +++ b/src/Instrumentation/KLN89/kln89_page.cxx @@ -204,6 +204,12 @@ void KLN89Page::SetId(const string& s) { _id = s; } +void KLN89Page::SetSubPage(int n) { + if(n < 0) n = 0; + if(n >= _nSubPages) n = _nSubPages-1; + _subPage = n; +} + const string& KLN89Page::GetId() { return(_id); } diff --git a/src/Instrumentation/KLN89/kln89_page.hxx b/src/Instrumentation/KLN89/kln89_page.hxx index a4e686ab8..89ea5a7e7 100644 --- a/src/Instrumentation/KLN89/kln89_page.hxx +++ b/src/Instrumentation/KLN89/kln89_page.hxx @@ -69,6 +69,7 @@ public: virtual const string& GetId(); inline int GetSubPage() { return(_subPage); } + void SetSubPage(int n); inline int GetNSubPages() { return(_nSubPages); } diff --git a/src/Instrumentation/KLN89/kln89_page_apt.cxx b/src/Instrumentation/KLN89/kln89_page_apt.cxx index 1f4ffcb8a..96cceea0d 100644 --- a/src/Instrumentation/KLN89/kln89_page_apt.cxx +++ b/src/Instrumentation/KLN89/kln89_page_apt.cxx @@ -643,8 +643,12 @@ void KLN89AptPage::ClrPressed() { void KLN89AptPage::EntPressed() { if(_entInvert) { _entInvert = false; - _last_apt_id = _apt_id; - _apt_id = _save_apt_id; + if(_kln89->_dtoReview) { + _kln89->DtoInitiate(_apt_id); + } else { + _last_apt_id = _apt_id; + _apt_id = _save_apt_id; + } } else if(_subPage == 7 && _kln89->_mode == KLN89_MODE_CRSR && _uLinePos > 0) { // We are selecting an approach if(_iafDialog) { diff --git a/src/Instrumentation/KLN89/kln89_page_dir.cxx b/src/Instrumentation/KLN89/kln89_page_dir.cxx index c80bd2397..a8382b06f 100644 --- a/src/Instrumentation/KLN89/kln89_page_dir.cxx +++ b/src/Instrumentation/KLN89/kln89_page_dir.cxx @@ -26,12 +26,14 @@ #endif #include "kln89_page_dir.hxx" +#include
KLN89DirPage::KLN89DirPage(KLN89* parent) : KLN89Page(parent) { _nSubPages = 1; _subPage = 0; _name = "DIR"; + _maxULinePos = 4; _DToWpDispMode = 2; } @@ -43,16 +45,16 @@ void KLN89DirPage::Update(double dt) { _kln89->DrawText("DIRECT TO:", 2, 2, 3); if(_kln89->_mode == KLN89_MODE_CRSR) { + string s = _id; + while(s.size() < 5) s += ' '; 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->DrawText(s, 2, 4, 1, false, _uLinePos); _kln89->DrawEnt(1, 0, 1); } _kln89->Underline(2, 4, 1, 5); @@ -67,13 +69,16 @@ void KLN89DirPage::Update(double dt) { KLN89Page::Update(dt); } +// This can only be called from the KLN89 when DTO is pressed from outside of the DIR page. +// DO NOT USE IT to set _id internally from the DIR page, since it initialises various state +// based on the assumption that the DIR page is being first entered. void KLN89DirPage::SetId(const 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! + if(!_kln89->_activeFP->IsEmpty()) { + _DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1; + } } else { _DToWpDispMode = 2; } @@ -81,6 +86,11 @@ void KLN89DirPage::SetId(const string& s) { _uLinePos = 1; // Needed to stop Leg flashing } +void KLN89DirPage::CrsrPressed() { + // Pressing CRSR clears the ID field (from sim). + _DToWpDispMode = 2; +} + void KLN89DirPage::ClrPressed() { if(_kln89->_mode == KLN89_MODE_CRSR) { if(_DToWpDispMode <= 1) { @@ -98,22 +108,115 @@ void KLN89DirPage::ClrPressed() { } void KLN89DirPage::EntPressed() { - //cout << "DTO ENT Pressed()\n"; - if(_id.empty()) { + // Trim any RH whitespace from _id + while(!_id.empty()) { + if(_id[_id.size()-1] == ' ') { + _id = _id.substr(0, _id.size()-1); + } else { + // Important to break, since usr waypoint names may contain space. + break; + } + } + if(_DToWpDispMode == 2 || _id.empty()) { _kln89->DtoCancel(); } else { - _kln89->DtoInitiate(_id); + if(_DToWpDispMode == 0) { + // It's a waypoint from the active flightplan - these get processed without data page review. + _kln89->DtoInitiate(_id); + } else { + // Display the appropriate data page for review (USR page if the ident is not currently valid) + _kln89->_dtoReview = true; + GPSWaypoint* wp = _kln89->FindFirstByExactId(_id); + if(wp) { + // Set the current page to be the appropriate data page + _kln89->_curPage = wp->type; + delete wp; + } else { + // Set the current page to be the user page + _kln89->_curPage = 4; + } + // set the page ID and entInvert, and activate the current page. + _kln89->_activePage = _kln89->_pages[_kln89->_curPage]; + _kln89->_activePage->SetId(_id); + _kln89->_activePage->SetEntInvert(true); + } } } void KLN89DirPage::Knob2Left1() { if(_kln89->_mode == KLN89_MODE_CRSR) { - if(_DToWpDispMode == 0) { - _DToWpDispMode = 1; - } else if(_DToWpDispMode == 1) { - // TODO + if(fgGetBool("/instrumentation/kln89/scan-pull")) { + if(_DToWpDispMode == 2) { + if(!_kln89->_activeFP->IsEmpty()) { + // Switch to mode 0, set the position to the end of the active flightplan *and* run the mode 0 case. + _DToWpDispMode = 0; + _DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1; + } + } + if(_DToWpDispMode == 0) { + // If the knob is pulled out, then the unit cycles through the waypoints of the active flight plan + // (This is deduced from the Bendix-King sim, I haven't found it documented in the pilot guide). + // If the active flight plan is empty it clears the field (this is possible, e.g. if a data page was + // active when DTO was pressed). + if(!_kln89->_activeFP->IsEmpty()) { + if(_DToWpDispIndex == 0) { + _DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1; + } else { + _DToWpDispIndex--; + } + _id = _kln89->_activeFP->waypoints[_DToWpDispIndex]->id; + } else { + _DToWpDispMode = 2; + } + } + // _DToWpDispMode == 1 is a NO-OP when the knob is out. } else { - // TODO + if(_DToWpDispMode == 0) { + // If the knob is not pulled out, then turning it transitions the DIR page to the waypoint selection mode + // and sets the waypoint to the first beginning with '9' + _id = "9"; + GPSWaypoint* wp = _kln89->FindFirstById(_id); + if(wp) { + _id = wp->id; + delete wp; + } + _uLinePos = 0; + _DToWpDispMode = 1; + } else if(_DToWpDispMode == 1) { + while(_id.size() < (_uLinePos + 1)) { + _id += ' '; + } + char ch = _id[_uLinePos]; + if(ch == ' ') { + ch = '9'; + } else if(ch == '0') { + ch = 'Z'; + } else if(ch == 'A') { + // It seems that blanks are allowed within the name, but not for the first character + if(_uLinePos == 0) { + ch = '9'; + } else { + ch = ' '; + } + } else { + ch--; + } + _id[_uLinePos] = ch; + GPSWaypoint* wp = _kln89->FindFirstById(_id.substr(0, _uLinePos+1)); + if(wp) { + _id = wp->id; + delete wp; + } + } else { + _id = "9"; + GPSWaypoint* wp = _kln89->FindFirstById(_id); + if(wp) { + _id = wp->id; + delete wp; + } + _uLinePos = 0; + _DToWpDispMode = 1; + } } } else { // If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed, @@ -125,12 +228,78 @@ void KLN89DirPage::Knob2Left1() { void KLN89DirPage::Knob2Right1() { if(_kln89->_mode == KLN89_MODE_CRSR) { - if(_DToWpDispMode == 0) { - _DToWpDispMode = 1; - } else if(_DToWpDispMode == 1) { - // TODO + if(fgGetBool("/instrumentation/kln89/scan-pull")) { + if(_DToWpDispMode == 2) { + if(!_kln89->_activeFP->IsEmpty()) { + // Switch to mode 0, set the position to the end of the active flightplan *and* run the mode 0 case. + _DToWpDispMode = 0; + _DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1; + } + } + if(_DToWpDispMode == 0) { + // If the knob is pulled out, then the unit cycles through the waypoints of the active flight plan + // (This is deduced from the Bendix-King sim, I haven't found it documented in the pilot guide). + // If the active flight plan is empty it clears the field (this is possible, e.g. if a data page was + // active when DTO was pressed). + if(!_kln89->_activeFP->IsEmpty()) { + if(_DToWpDispIndex == (int)_kln89->_activeFP->waypoints.size() - 1) { + _DToWpDispIndex = 0; + } else { + _DToWpDispIndex++; + } + _id = _kln89->_activeFP->waypoints[_DToWpDispIndex]->id; + } else { + _DToWpDispMode = 2; + } + } + // _DToWpDispMode == 1 is a NO-OP when the knob is out. } else { - // TODO + if(_DToWpDispMode == 0) { + // If the knob is not pulled out, then turning it transitions the DIR page to the waypoint selection mode + // and sets the waypoint to the first beginning with 'A' + _id = "A"; + GPSWaypoint* wp = _kln89->FindFirstById(_id); + if(wp) { + _id = wp->id; + delete wp; + } + _uLinePos = 0; + _DToWpDispMode = 1; + } else if(_DToWpDispMode == 1) { + while(_id.size() < (_uLinePos + 1)) { + _id += ' '; + } + char ch = _id[_uLinePos]; + if(ch == ' ') { + ch = 'A'; + } else if(ch == 'Z') { + ch = '0'; + } else if(ch == '9') { + // It seems that blanks are allowed within the name, but not for the first character + if(_uLinePos == 0) { + ch = 'A'; + } else { + ch = ' '; + } + } else { + ch++; + } + _id[_uLinePos] = ch; + GPSWaypoint* wp = _kln89->FindFirstById(_id.substr(0, _uLinePos+1)); + if(wp) { + _id = wp->id; + delete wp; + } + } else { + _id = "A"; + GPSWaypoint* wp = _kln89->FindFirstById(_id); + if(wp) { + _id = wp->id; + delete wp; + } + _uLinePos = 0; + _DToWpDispMode = 1; + } } } else { // If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed, diff --git a/src/Instrumentation/KLN89/kln89_page_dir.hxx b/src/Instrumentation/KLN89/kln89_page_dir.hxx index fe8f18261..ac5899327 100644 --- a/src/Instrumentation/KLN89/kln89_page_dir.hxx +++ b/src/Instrumentation/KLN89/kln89_page_dir.hxx @@ -36,6 +36,7 @@ public: void SetId(const string& s); + void CrsrPressed(); void ClrPressed(); void EntPressed(); void Knob2Left1(); @@ -49,6 +50,10 @@ private: // 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; + // Position of the list in the mode that scans through the active flight plan. + // This should be initialised to point at the final waypoint of the active flight plan when we enter mode zero above. + int _DToWpDispIndex; + // We need to save the mode when DTO gets pressed, since potentially this class handles page exit via. the CLR event handler KLN89Mode _saveMasterMode; }; diff --git a/src/Instrumentation/KLN89/kln89_page_int.cxx b/src/Instrumentation/KLN89/kln89_page_int.cxx index 694e06ce6..1edb2428d 100644 --- a/src/Instrumentation/KLN89/kln89_page_int.cxx +++ b/src/Instrumentation/KLN89/kln89_page_int.cxx @@ -195,8 +195,13 @@ void KLN89IntPage::ClrPressed() { void KLN89IntPage::EntPressed() { if(_entInvert) { _entInvert = false; - _last_int_id = _int_id; - _int_id = _save_int_id; + _entInvert = false; + if(_kln89->_dtoReview) { + _kln89->DtoInitiate(_int_id); + } else { + _last_int_id = _int_id; + _int_id = _save_int_id; + } } } diff --git a/src/Instrumentation/KLN89/kln89_page_ndb.cxx b/src/Instrumentation/KLN89/kln89_page_ndb.cxx index 0a70f1d63..b6b90bebd 100644 --- a/src/Instrumentation/KLN89/kln89_page_ndb.cxx +++ b/src/Instrumentation/KLN89/kln89_page_ndb.cxx @@ -158,8 +158,12 @@ void KLN89NDBPage::ClrPressed() { void KLN89NDBPage::EntPressed() { if(_entInvert) { _entInvert = false; - _last_ndb_id = _ndb_id; - _ndb_id = _save_ndb_id; + if(_kln89->_dtoReview) { + _kln89->DtoInitiate(_ndb_id); + } else { + _last_ndb_id = _ndb_id; + _ndb_id = _save_ndb_id; + } } } diff --git a/src/Instrumentation/KLN89/kln89_page_vor.cxx b/src/Instrumentation/KLN89/kln89_page_vor.cxx index a7719f495..414a8c487 100644 --- a/src/Instrumentation/KLN89/kln89_page_vor.cxx +++ b/src/Instrumentation/KLN89/kln89_page_vor.cxx @@ -170,8 +170,13 @@ void KLN89VorPage::ClrPressed() { void KLN89VorPage::EntPressed() { if(_entInvert) { _entInvert = false; - _last_vor_id = _vor_id; - _vor_id = _save_vor_id; + _entInvert = false; + if(_kln89->_dtoReview) { + _kln89->DtoInitiate(_vor_id); + } else { + _last_vor_id = _vor_id; + _vor_id = _save_vor_id; + } } } diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index 6feb0a286..d3da8e828 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -717,21 +717,25 @@ double DCLGPS::GetCDIDeflection() const { } void DCLGPS::DtoInitiate(const string& s) { - //cout << "DtoInitiate, s = " << s << '\n'; const GPSWaypoint* wp = FindFirstByExactId(s); if(wp) { - //cout << "Waypoint found, starting dto operation!\n"; + // TODO - Currently we start DTO operation unconditionally, regardless of which mode we are in. + // In fact, the following rules apply: + // In LEG mode, start DTO as we currently do. + // In OBS mode, set the active waypoint to the requested waypoint, and then: + // If the KLN89 is not connected to an external HSI or CDI, set the OBS course to go direct to the waypoint. + // If the KLN89 *is* connected to an external HSI or CDI, it cannot set the course itself, and will display + // a scratchpad message with the course to set manually on the HSI/CDI. + // In both OBS cases, leave _dto false, since we don't need the virtual waypoint created. _dto = true; _activeWaypoint = *wp; _fromWaypoint.lat = _gpsLat; _fromWaypoint.lon = _gpsLon; _fromWaypoint.type = GPS_WP_VIRT; _fromWaypoint.id = "DTOWP"; - delete wp; + delete wp; } else { - //cout << "Waypoint not found, ignoring dto request\n"; - // Should bring up the user waypoint page, but we're not implementing that yet. - _dto = false; // TODO - implement this some day. + _dto = false; } } diff --git a/src/Instrumentation/dclgps.hxx b/src/Instrumentation/dclgps.hxx index 76dd764dd..295a7ad64 100644 --- a/src/Instrumentation/dclgps.hxx +++ b/src/Instrumentation/dclgps.hxx @@ -287,7 +287,7 @@ public: inline bool GetToFlag() const { return(_headingBugTo); } // Initiate Direct To operation to the supplied ID. - void DtoInitiate(const string& id); + virtual void DtoInitiate(const string& id); // Cancel Direct To operation void DtoCancel(); @@ -343,8 +343,8 @@ protected: protected: // Find first of any type of waypoint by id. (TODO - Possibly we should return multiple waypoints here). - GPSWaypoint* FindFirstById(const string& id) const; - GPSWaypoint* FindFirstByExactId(const string& id) const; + GPSWaypoint* FindFirstById(const string& id) const; + GPSWaypoint* FindFirstByExactId(const string& id) const; FGNavRecord* FindFirstVorById(const string& id, bool &multi, bool exact = false); FGNavRecord* FindFirstNDBById(const string& id, bool &multi, bool exact = false); @@ -353,8 +353,8 @@ protected: // Find the closest VOR to a position in RADIANS. FGNavRecord* FindClosestVor(double lat_rad, double lon_rad); - // helper to implement the above FindFirstXXX methods - FGPositioned* FindTypedFirstById(const std::string& id, FGPositioned::Type ty, bool &multi, bool exact); + // helper to implement the above FindFirstXXX methods + FGPositioned* FindTypedFirstById(const std::string& id, FGPositioned::Type ty, bool &multi, bool exact); // Position, orientation and velocity. // These should be read from FG's built-in GPS logic if possible.