]> git.mxchange.org Git - flightgear.git/blobdiff - src/Instrumentation/dclgps.cxx
remove old .cvsignore files
[flightgear.git] / src / Instrumentation / dclgps.cxx
index 3156c55ac531f6cfd58e40898dd2d80a33963aee..41697092b3e928f8f27bec73f419d598dff91f1c 100644 (file)
@@ -26,7 +26,6 @@
 #include "dclgps.hxx"
 
 #include <simgear/sg_inlines.h>
-#include <simgear/structure/commands.hxx>
 #include <simgear/timing/sg_time.hxx>
 #include <simgear/magvar/magvar.hxx>
 
 #include <Navaids/fix.hxx>
 #include <Navaids/navrecord.hxx>
 #include <Airports/simple.hxx>
+#include <Airports/runways.hxx>
 
 #include <iostream>
 
 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<string> ids, vector<GPSW
                case GPS_WP_USR:
                        // TODO
                        break;
+               case GPS_WP_VIRT:
+                       // TODO
+                       break;
                }
        }
 }
@@ -1075,7 +1102,8 @@ FGPositioned* DCLGPS::FindTypedFirstById(const string& id, FGPositioned::Type ty
   
   if (exact) {
     FGPositioned::List matches = 
-      FGPositioned::findAllWithIdentSortedByRange(id, SGGeod::fromRad(_lon, _lat), &filter);
+      FGPositioned::findAllWithIdent(id, &filter);
+    FGPositioned::sortByRange(matches, SGGeod::fromRad(_lon, _lat));
     multi = (matches.size() > 1);
     return matches.empty() ? NULL : matches.front().ptr();
   }