X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInstrumentation%2Fdclgps.cxx;h=41697092b3e928f8f27bec73f419d598dff91f1c;hb=0a5e86f4e61a80ff19b78de011852a7b60250b7a;hp=3156c55ac531f6cfd58e40898dd2d80a33963aee;hpb=871b92ae339b33a2c6ee5ede4a61dbc39c9ca3f3;p=flightgear.git diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index 3156c55ac..41697092b 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -26,7 +26,6 @@ #include "dclgps.hxx" #include -#include #include #include @@ -34,90 +33,12 @@ #include #include #include +#include #include using namespace std; -// Command callbacks for FlightGear - -static bool do_kln89_msg_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_msg_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->MsgPressed(); - return(true); -} - -static bool do_kln89_obs_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_obs_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->OBSPressed(); - return(true); -} - -static bool do_kln89_alt_pressed(const SGPropertyNode* arg) { - //cout << "do_kln89_alt_pressed called!\n"; - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->AltPressed(); - return(true); -} - -static bool do_kln89_nrst_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->NrstPressed(); - return(true); -} - -static bool do_kln89_dto_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->DtoPressed(); - return(true); -} - -static bool do_kln89_clr_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->ClrPressed(); - return(true); -} - -static bool do_kln89_ent_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->EntPressed(); - return(true); -} - -static bool do_kln89_crsr_pressed(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->CrsrPressed(); - return(true); -} - -static bool do_kln89_knob1left1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob1Left1(); - return(true); -} - -static bool do_kln89_knob1right1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob1Right1(); - return(true); -} - -static bool do_kln89_knob2left1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob2Left1(); - return(true); -} - -static bool do_kln89_knob2right1(const SGPropertyNode* arg) { - DCLGPS* gps = (DCLGPS*)globals->get_subsystem("kln89"); - gps->Knob2Right1(); - return(true); -} - -// End command callbacks - GPSWaypoint::GPSWaypoint() { appType = GPS_APP_NONE; } @@ -222,59 +143,12 @@ ClockTime::ClockTime(int hr, int min) { ClockTime::~ClockTime() { } -GPSPage::GPSPage(DCLGPS* parent) { - _parent = parent; - _subPage = 0; -} - -GPSPage::~GPSPage() { -} - -void GPSPage::Update(double dt) {} - -void GPSPage::Knob1Left1() {} -void GPSPage::Knob1Right1() {} - -void GPSPage::Knob2Left1() { - _parent->_activePage->LooseFocus(); - _subPage--; - if(_subPage < 0) _subPage = _nSubPages - 1; -} - -void GPSPage::Knob2Right1() { - _parent->_activePage->LooseFocus(); - _subPage++; - if(_subPage >= _nSubPages) _subPage = 0; -} - -void GPSPage::CrsrPressed() {} -void GPSPage::EntPressed() {} -void GPSPage::ClrPressed() {} -void GPSPage::DtoPressed() {} -void GPSPage::NrstPressed() {} -void GPSPage::AltPressed() {} -void GPSPage::OBSPressed() {} -void GPSPage::MsgPressed() {} - -string GPSPage::GPSitoa(int n) { - char buf[4]; - // TODO - sanity check n! - sprintf(buf, "%i", n); - string s = buf; - return(s); -} - -void GPSPage::CleanUp() {} -void GPSPage::LooseFocus() {} -void GPSPage::SetId(const string& s) {} - // ------------------------------------------------------------------------------------- // DCLGPS::DCLGPS(RenderArea2D* instrument) { _instrument = instrument; _nFields = 1; _maxFields = 2; - _pages.clear(); // Units - lets default to US units - FG can set them to other units from config during startup if desired. _altUnits = GPS_ALT_UNITS_FT; @@ -357,27 +231,104 @@ DCLGPS::~DCLGPS() { // TODO - may need to delete the approach database!! } -void DCLGPS::draw() { - //cout << "draw called!\n"; - _instrument->draw(); +void DCLGPS::draw(osg::State& state) { + _instrument->draw(state); } void DCLGPS::init() { - globals->get_commands()->addCommand("kln89_msg_pressed", do_kln89_msg_pressed); - globals->get_commands()->addCommand("kln89_obs_pressed", do_kln89_obs_pressed); - globals->get_commands()->addCommand("kln89_alt_pressed", do_kln89_alt_pressed); - globals->get_commands()->addCommand("kln89_nrst_pressed", do_kln89_nrst_pressed); - globals->get_commands()->addCommand("kln89_dto_pressed", do_kln89_dto_pressed); - globals->get_commands()->addCommand("kln89_clr_pressed", do_kln89_clr_pressed); - globals->get_commands()->addCommand("kln89_ent_pressed", do_kln89_ent_pressed); - globals->get_commands()->addCommand("kln89_crsr_pressed", do_kln89_crsr_pressed); - globals->get_commands()->addCommand("kln89_knob1left1", do_kln89_knob1left1); - globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1); - globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1); - globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1); // 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->_aptIdent = "KHAF"; + iap->_ident = "R12-Y"; + iap->_name = ExpandSIAPIdent(iap->_ident); + iap->_rwyStr = "12"; + iap->_approachRoutes.clear(); + iap->_IAP.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->_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)); + 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->_IAP.push_back(wp); + } else { + //cout << "Unable to find waypoint " << wp->id << '\n'; + } + // ------- + _np_iap[iap->_aptIdent].push_back(iap); } void DCLGPS::bind() { @@ -661,6 +612,88 @@ 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 = false; + + 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; +} + +// Returns meters +float DCLGPS::GetDistToActiveWaypoint() { + return _dist2Act; +} + // I don't yet fully understand all the gotchas about where to source time from. // This function sets the initial timer before the clock exports properties // and the one below uses the clock to be consistent with the rest of the code. @@ -684,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; } } @@ -711,18 +748,7 @@ void DCLGPS::DtoCancel() { _dto = false; } -void DCLGPS::Knob1Left1() {} -void DCLGPS::Knob1Right1() {} -void DCLGPS::Knob2Left1() {} -void DCLGPS::Knob2Right1() {} -void DCLGPS::CrsrPressed() { _activePage->CrsrPressed(); } -void DCLGPS::EntPressed() { _activePage->EntPressed(); } -void DCLGPS::ClrPressed() { _activePage->ClrPressed(); } -void DCLGPS::DtoPressed() {} -void DCLGPS::NrstPressed() {} -void DCLGPS::AltPressed() {} - -void DCLGPS::OBSPressed() { +void DCLGPS::ToggleOBSMode() { _obsMode = !_obsMode; if(_obsMode) { if(!_activeWaypoint.id.empty()) { @@ -744,8 +770,6 @@ void DCLGPS::SetOBSFromWaypoint() { _fromWaypoint.id = "OBSWP"; } -void DCLGPS::MsgPressed() {} - void DCLGPS::CDIFSDIncrease() { if(_currentCdiScaleIndex == 0) { _currentCdiScaleIndex = _cdiScales.size() - 1; @@ -1029,6 +1053,9 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector ids, vector 1); return matches.empty() ? NULL : matches.front().ptr(); }