]> git.mxchange.org Git - flightgear.git/blobdiff - src/Instrumentation/dclgps.cxx
Make various PUI widgets private.
[flightgear.git] / src / Instrumentation / dclgps.cxx
index 92dcb21325bb442152701d02cf6d311005f281ed..aeeb54fdc9534b322257aa15cb68e39b5b090dcd 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <cstdlib>
 
 using namespace std;
 
@@ -152,12 +153,6 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) {
        _instrument = instrument;
        _nFields = 1;
        _maxFields = 2;
-       
-       // Units - lets default to US units - FG can set them to other units from config during startup if desired.
-       _altUnits = GPS_ALT_UNITS_FT;
-       _baroUnits = GPS_PRES_UNITS_IN;
-       _velUnits = GPS_VEL_UNITS_KT;
-       _distUnits = GPS_DIST_UNITS_NM;
 
        _lon_node = fgGetNode("/instrumentation/gps/indicated-longitude-deg", true);
        _lat_node = fgGetNode("/instrumentation/gps/indicated-latitude-deg", true);
@@ -211,11 +206,7 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) {
        // Configuration Initialisation
        // Should this be in kln89.cxx ?
        _turnAnticipationEnabled = false;
-       _suaAlertEnabled = false;
-       _altAlertEnabled = false;
-        
-       _time = new SGTime;
-       
+               
        _messageStack.clear();
        
        _dto = false;
@@ -228,7 +219,6 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) {
 }
 
 DCLGPS::~DCLGPS() {
-       delete _time;
   delete _approachFP;          // Don't need to delete the waypoints inside since they point to
                                                        // the waypoints in the approach database.
        // TODO - may need to delete the approach database!!
@@ -247,22 +237,18 @@ void DCLGPS::init() {
 }
 
 void DCLGPS::bind() {
-       fgTie("/instrumentation/gps/waypoint-alert", this, &DCLGPS::GetWaypointAlert);
-       fgTie("/instrumentation/gps/leg-mode", this, &DCLGPS::GetLegMode);
-       fgTie("/instrumentation/gps/obs-mode", this, &DCLGPS::GetOBSMode);
-       fgTie("/instrumentation/gps/approach-arm", this, &DCLGPS::GetApproachArm);
-       fgTie("/instrumentation/gps/approach-active", this, &DCLGPS::GetApproachActive);
-       fgTie("/instrumentation/gps/cdi-deflection", this, &DCLGPS::GetCDIDeflection);
-       fgTie("/instrumentation/gps/to-flag", this, &DCLGPS::GetToFlag);
+       _tiedProperties.setRoot(fgGetNode("/instrumentation/gps", true));
+       _tiedProperties.Tie("waypoint-alert",  this, &DCLGPS::GetWaypointAlert);
+       _tiedProperties.Tie("leg-mode",        this, &DCLGPS::GetLegMode);
+       _tiedProperties.Tie("obs-mode",        this, &DCLGPS::GetOBSMode);
+       _tiedProperties.Tie("approach-arm",    this, &DCLGPS::GetApproachArm);
+       _tiedProperties.Tie("approach-active", this, &DCLGPS::GetApproachActive);
+       _tiedProperties.Tie("cdi-deflection",  this, &DCLGPS::GetCDIDeflection);
+       _tiedProperties.Tie("to-flag",         this, &DCLGPS::GetToFlag);
 }
 
 void DCLGPS::unbind() {
-       fgUntie("/instrumentation/gps/waypoint-alert");
-       fgUntie("/instrumentation/gps/leg-mode");
-       fgUntie("/instrumentation/gps/obs-mode");
-       fgUntie("/instrumentation/gps/approach-arm");
-       fgUntie("/instrumentation/gps/approach-active");
-       fgUntie("/instrumentation/gps/cdi-deflection");
+       _tiedProperties.Untie();
 }
 
 void DCLGPS::update(double dt) {
@@ -316,7 +302,6 @@ void DCLGPS::update(double dt) {
                _elapsedTime += dt;
        }
 
-       _time->update(_gpsLon * SG_DEGREES_TO_RADIANS, _gpsLat * SG_DEGREES_TO_RADIANS, 0, 0);
        // FIXME - currently all the below assumes leg mode and no DTO or OBS cancelled.
        if(_activeFP->IsEmpty()) {
                // Not sure if we need to reset these each update or only when fp altered
@@ -491,8 +476,7 @@ void DCLGPS::update(double dt) {
                                                _fromWaypoint = _activeWaypoint;
                                                _activeWaypoint = *_activeFP->waypoints[idx + 1];
                                                _dto = false;
-                                               // TODO - course alteration message format is dependent on whether we are slaved HSI/CDI indicator or not.
-                                               // For now assume we are not.
+                                               // Course alteration message format is dependent on whether we are slaved HSI/CDI indicator or not.
                                                string s;
                                                if(fgGetBool("/instrumentation/nav[0]/slaved-to-gps")) {
                                                        // TODO - avoid the hardwiring on nav[0]
@@ -601,7 +585,8 @@ string DCLGPS::ExpandSIAPIdent(const string& ident) {
 }
 
 /*
-       Load instrument approaches from an ARINC 424-18 file.
+       Load instrument approaches from an ARINC 424 file.
+       Tested on ARINC 424-18.
        Known / current best guess at the format:
        Col 1:          Always 'S'.  If it isn't, ditch it.
        Col 2-4:        "Customer area" code, eg "USA", "CAN".  I think that CAN is used for Alaska.
@@ -662,7 +647,7 @@ string DCLGPS::ExpandSIAPIdent(const string& ident) {
        Col 107-111     MSA center fix.  We can ignore this.
 */
 void DCLGPS::LoadApproachData() {
-       FGNPIAP* iap;
+       FGNPIAP* iap = NULL;
        GPSWaypoint* wp;
        GPSFlightPlan* fp;
        const GPSWaypoint* cwp;
@@ -672,10 +657,10 @@ void DCLGPS::LoadApproachData() {
        path.append("Navaids/rnav.dat");
        fin.open(path.c_str(), ios::in);
        if(!fin) {
-               cout << "Unable to open input file " << path.c_str() << '\n';
+               //cout << "Unable to open input file " << path.c_str() << '\n';
                return;
        } else {
-               cout << "Opened " << path.c_str() << " for reading\n";
+               //cout << "Opened " << path.c_str() << " for reading\n";
        }
        char tmp[256];
        string s;
@@ -726,7 +711,7 @@ void DCLGPS::LoadApproachData() {
                                                        if(last_apt_ident != apt_ident) {
                                                                if(iap_in_progress) {
                                                                        if(iap_error) {
-                                                                               cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
+                                                                               //cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
                                                                                nErrors++;
                                                                        } else {
                                                                                _np_iap[iap->_aptIdent].push_back(iap);
@@ -756,7 +741,7 @@ void DCLGPS::LoadApproachData() {
                                                                        // This is a new approach - store the last one and trigger
                                                                        // starting afresh by setting the in progress flag to false.
                                                                        if(iap_error) {
-                                                                               cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
+                                                                               //cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
                                                                                nErrors++;
                                                                        } else {
                                                                                _np_iap[iap->_aptIdent].push_back(iap);
@@ -803,13 +788,21 @@ void DCLGPS::LoadApproachData() {
                                                                        // Note: Currently fgFindAirportID returns NULL on error, but getRunwayByIdent throws an exception.
                                                                        const FGAirport* apt = fgFindAirportID(iap->_aptIdent);
                                                                        if(apt) {
+                                                                               string rwystr;
                                                                                try {
-                                                                                       // TODO - sanity check the waypoint ID to ensure we have a double digit number
-                                                                                       FGRunway* rwy = apt->getRunwayByIdent(w.id.substr(2, 2));
+                                                                                       rwystr = w.id.substr(2, 2);
+                                                                                       // TODO - sanity check the rwystr at this point to ensure we have a double digit number
+                                                                                       if(w.id.size() > 4) {
+                                                                                               if(w.id[4] == 'L' || w.id[4] == 'C' || w.id[4] == 'R') {
+                                                                                                       rwystr += w.id[4];
+                                                                                               }
+                                                                                       }
+                                                                                       FGRunway* rwy = apt->getRunwayByIdent(rwystr);
                                                                                        w.lat = rwy->begin().getLatitudeRad();
                                                                                        w.lon = rwy->begin().getLongitudeRad();
                                                                                } catch(const sg_exception&) {
-                                                                                       SG_LOG(SG_GENERAL, SG_WARN, "Unable to find runway " << w.id.substr(2, 2) << " at airport " << iap->_aptIdent);
+                                                                                       SG_LOG(SG_INSTR, SG_WARN, "Unable to find runway " << w.id.substr(2, 2) << " at airport " << iap->_aptIdent);
+                                                                                       //cout << "Unable to find runway " << w.id.substr(2, 2) << " at airport " << iap->_aptIdent << " ( w.id = " << w.id << ", rwystr = " << rwystr << " )\n";
                                                                                        wp_error = true;
                                                                                }
                                                                        } else {
@@ -850,7 +843,7 @@ void DCLGPS::LoadApproachData() {
                                                                                                                if(iap->_IAP[iap->_IAP.size() - 1]->appType == GPS_APP_NONE) {
                                                                                                                        iap->_IAP[iap->_IAP.size() - 1]->appType = GPS_MAHP;
                                                                                                                } else {
-                                                                                                                       cout << "Waypoint is MAHP and another type! " << w.id << " [" << apt_ident << ", " << iap_ident << "]\n";
+                                                                                                                       //cout << "Waypoint is MAHP and another type! " << w.id << " [" << apt_ident << ", " << iap_ident << "]\n";
                                                                                                                }
                                                                                                        }
                                                                                                }
@@ -922,7 +915,7 @@ void DCLGPS::LoadApproachData() {
                                                // This is a new approach - store the last one and trigger
                                                // starting afresh by setting the in progress flag to false.
                                                if(iap_error) {
-                                                       cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
+                                                       //cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
                                                        nErrors++;
                                                } else {
                                                        _np_iap[iap->_aptIdent].push_back(iap);
@@ -940,7 +933,7 @@ void DCLGPS::LoadApproachData() {
        // TODO - sanity check that the approach has all the required elements
        if(iap_in_progress) {
                if(iap_error) {
-                       cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
+                       //cout << "ERROR: Unable to load approach " << iap->_ident << " at " << iap->_aptIdent << '\n';
                        nErrors++;
                } else {
                        _np_iap[iap->_aptIdent].push_back(iap);
@@ -949,9 +942,9 @@ void DCLGPS::LoadApproachData() {
                }
        }
        
-       cout << "Done loading approach database\n";
-       cout << "Loaded: " << nLoaded << '\n';
-       cout << "Failed: " << nErrors << '\n';
+       //cout << "Done loading approach database\n";
+       //cout << "Loaded: " << nLoaded << '\n';
+       //cout << "Failed: " << nErrors << '\n';
        
        fin.close();
 }
@@ -1003,7 +996,7 @@ void DCLGPS::DtoInitiate(const string& s) {
                _fromWaypoint.lat = _gpsLat;
                _fromWaypoint.lon = _gpsLon;
                _fromWaypoint.type = GPS_WP_VIRT;
-               _fromWaypoint.id = "DTOWP";
+               _fromWaypoint.id = "_DTOWP_";
                delete wp;
        } else {
                // TODO - Should bring up the user waypoint page.
@@ -1023,9 +1016,37 @@ void DCLGPS::DtoCancel() {
 void DCLGPS::ToggleOBSMode() {
        _obsMode = !_obsMode;
        if(_obsMode) {
-               if(!_activeWaypoint.id.empty()) {
-                       _obsHeading = static_cast<int>(_dtkMag);
+               // We need to set the OBS heading.  The rules for this are:
+               //
+               // If the KLN89 is connected to an external HSI or CDI, then the OBS heading must be set
+               // to the OBS radial on the external indicator, and cannot be changed in the KLN89.
+               //
+               // If the KLN89 is not connected to an external indicator, then:
+               //              If there is an active waypoint, the OBS heading is set such that the
+               //              deviation indicator remains at the same deviation (i.e. set to DTK, 
+               //              although there may be some small difference).
+               //
+               //              If there is not an active waypoint, I am not sure what value should be
+               //              set.
+               //
+               if(fgGetBool("/instrumentation/nav/slaved-to-gps")) {
+                       _obsHeading = static_cast<int>(fgGetDouble("/instrumentation/nav/radials/selected-deg") + 0.5);
+               } else if(!_activeWaypoint.id.empty()) {
+                       // NOTE: I am not sure if this is completely correct.  There are sometimes small differences
+                       // between DTK and default OBS heading in the simulator (~ 1 or 2 degrees).  It might also
+                       // be that OBS heading should be stored as float and only displayed as int, in order to maintain
+                       // the initial bar deviation?
+                       _obsHeading = static_cast<int>(_dtkMag + 0.5);
+                       //cout << "_dtkMag = " << _dtkMag << ", _dtkTrue = " << _dtkTrue << ", _obsHeading = " << _obsHeading << '\n';
+               } else {
+                       // TODO - what should we really do here?
+                       _obsHeading = 0;
                }
+               
+               // Valid OBS heading values are 0 -> 359 degrees inclusive (from kln89 simulator).
+               if(_obsHeading > 359) _obsHeading -= 360;
+               if(_obsHeading < 0) _obsHeading += 360;
+               
                // TODO - the _fromWaypoint location will change as the OBS heading changes.
                // Might need to store the OBS initiation position somewhere in case it is needed again.
                SetOBSFromWaypoint();
@@ -1039,7 +1060,8 @@ void DCLGPS::SetOBSFromWaypoint() {
        
        // TODO - base the 180 deg correction on the to/from flag.
        _fromWaypoint = GetPositionOnMagRadial(_activeWaypoint, 10, _obsHeading + 180.0);
-       _fromWaypoint.id = "OBSWP";
+       _fromWaypoint.type = GPS_WP_VIRT;
+       _fromWaypoint.id = "_OBSWP_";
 }
 
 void DCLGPS::CDIFSDIncrease() {
@@ -1063,16 +1085,6 @@ void DCLGPS::DrawChar(char c, int field, int px, int py, bool bold) {
 void DCLGPS::DrawText(const string& s, int field, int px, int py, bool bold) {
 }
 
-void DCLGPS::SetBaroUnits(int n, bool wrap) {
-       if(n < 1) {
-               _baroUnits = (GPSPressureUnits)(wrap ? 3 : 1);
-       } else if(n > 3) {
-               _baroUnits = (GPSPressureUnits)(wrap ? 1 : 3);
-       } else {
-               _baroUnits = (GPSPressureUnits)n;
-       }
-}
-
 void DCLGPS::CreateDefaultFlightPlans() {}
 
 // Get the time to the active waypoint in seconds.
@@ -1337,7 +1349,8 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector<string> ids, vector<GPSW
 class DCLGPSFilter : public FGPositioned::Filter
 {
 public:
-  virtual bool pass(const FGPositioned* aPos) const {
+  virtual bool pass(FGPositioned* aPos) const
+  {
     switch (aPos->type()) {
     case FGPositioned::AIRPORT:
     // how about heliports and seaports?
@@ -1354,9 +1367,14 @@ public:
 
 GPSWaypoint* DCLGPS::FindFirstById(const string& id) const
 {
-  DCLGPSFilter filter;
-  FGPositionedRef result = FGPositioned::findNextWithPartialId(NULL, id, &filter);
-  return GPSWaypoint::createFromPositioned(result);
+  DCLGPSFilter filter;  
+  FGPositioned::List matches = FGPositioned::findAllWithIdent(id, &filter, false);
+  if (matches.empty()) {
+    return NULL;
+  }
+  
+  FGPositioned::sortByRange(matches, SGGeod::fromRad(_lon, _lat));
+  return GPSWaypoint::createFromPositioned(matches.front());
 }
 
 GPSWaypoint* DCLGPS::FindFirstByExactId(const string& id) const
@@ -1372,15 +1390,14 @@ FGPositioned* DCLGPS::FindTypedFirstById(const string& id, FGPositioned::Type ty
   multi = false;
   FGPositioned::TypeFilter filter(ty);
   
-  if (exact) {
-    FGPositioned::List matches = 
-      FGPositioned::findAllWithIdent(id, &filter);
-    FGPositioned::sortByRange(matches, SGGeod::fromRad(_lon, _lat));
-    multi = (matches.size() > 1);
-    return matches.empty() ? NULL : matches.front().ptr();
+  FGPositioned::List matches =
+    FGPositioned::findAllWithIdent(id, &filter, exact);
+  if (matches.empty()) {
+    return NULL;
   }
   
-  return FGPositioned::findNextWithPartialId(NULL, id, &filter);
+  FGPositioned::sortByRange(matches, SGGeod::fromRad(_lon, _lat));
+  return matches.front();
 }
 
 FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact)
@@ -1422,7 +1439,8 @@ double DCLGPS::GetMagHeadingFromTo(double latA, double lonA, double latB, double
        h *= SG_RADIANS_TO_DEGREES;
        // TODO - use the real altitude below instead of 0.0!
        //cout << "MagVar = " << sgGetMagVar(_gpsLon, _gpsLat, 0.0, _time->getJD()) * SG_RADIANS_TO_DEGREES << '\n';
-       h -= sgGetMagVar(_gpsLon, _gpsLat, 0.0, _time->getJD()) * SG_RADIANS_TO_DEGREES;
+  double jd = globals->get_time_params()->getJD();
+       h -= sgGetMagVar(_gpsLon, _gpsLat, 0.0, jd) * SG_RADIANS_TO_DEGREES;
        while(h >= 360.0) h -= 360.0;
        while(h < 0.0) h += 360.0;
        return(h);
@@ -1504,7 +1522,8 @@ double DCLGPS::GetGreatCircleCourse (double lat1, double lon1, double lat2, doub
 // Return a position on a radial from wp1 given distance d (nm) and magnetic heading h (degrees)
 // Note that d should be less that 1/4 Earth diameter!
 GPSWaypoint DCLGPS::GetPositionOnMagRadial(const GPSWaypoint& wp1, double d, double h) {
-       h += sgGetMagVar(wp1.lon, wp1.lat, 0.0, _time->getJD()) * SG_RADIANS_TO_DEGREES;
+  double jd = globals->get_time_params()->getJD();
+       h += sgGetMagVar(wp1.lon, wp1.lat, 0.0, jd) * SG_RADIANS_TO_DEGREES;
        return(GetPositionOnRadial(wp1, d, h));
 }