#endif
#include "kln89_page_dir.hxx"
+#include <Main/fg_props.hxx>
KLN89DirPage::KLN89DirPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 1;
_subPage = 0;
_name = "DIR";
+ _maxULinePos = 4;
_DToWpDispMode = 2;
}
_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);
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;
}
_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) {
}
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,
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,
}
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;
}
}
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();
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);
// 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.