]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/FGFDMExec.cpp
Fix stall widths for the "auxilliary" (reverse flow) stalls so they
[flightgear.git] / src / FDM / JSBSim / FGFDMExec.cpp
index fdf6eaf2cd7acbdb7072440e04626ad78275cf6a..2110fb0d9559006bbc2933875c7568e1de163b5d 100644 (file)
@@ -46,7 +46,7 @@ INCLUDES
 #  include STL_IOSTREAM
 #  include STL_ITERATOR
 #else
-#  if defined(sgi) && !defined(__GNUC__)
+#  if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
 #    include <iostream.h>
 #  else
 #    include <iostream>
@@ -58,19 +58,21 @@ INCLUDES
 #include "FGState.h"
 #include "FGAtmosphere.h"
 #include "FGFCS.h"
+#include "FGGroundCallback.h"
 #include "FGPropulsion.h"
 #include "FGMassBalance.h"
 #include "FGGroundReactions.h"
 #include "FGAerodynamics.h"
 #include "FGInertial.h"
 #include "FGAircraft.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
 #include "FGAuxiliary.h"
 #include "FGOutput.h"
 #include "FGConfigFile.h"
 #include "FGInitialCondition.h"
+#include "FGPropertyManager.h"
+
+namespace JSBSim {
 
 static const char *IdSrc = "$Id$";
 static const char *IdHdr = ID_FDMEXEC;
@@ -80,15 +82,33 @@ GLOBAL DECLARATIONS
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 unsigned int FGFDMExec::FDMctr = 0;
+FGPropertyManager* FGFDMExec::master=0;
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS IMPLEMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
+void checkTied ( FGPropertyManager *node )
+{
+  int N = node->nChildren();
+  string name;
+
+  for (int i=0; i<N; i++) {
+    if (node->getChild(i)->nChildren() ) {
+      checkTied( (FGPropertyManager*)node->getChild(i) );
+    } else if ( node->getChild(i)->isTied() ) {
+      name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
+      cerr << name << " is tied" << endl;
+    }
+  }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 // Constructor
 
-FGFDMExec::FGFDMExec(void)
+FGFDMExec::FGFDMExec(FGPropertyManager* root)
 {
+
   Frame           = 0;
   FirstModel      = 0;
   Error           = 0;
@@ -101,37 +121,63 @@ FGFDMExec::FGFDMExec(void)
   Inertial        = 0;
   GroundReactions = 0;
   Aircraft        = 0;
-  Translation     = 0;
-  Rotation        = 0;
-  Position        = 0;
+  GroundCallback  = 0;
+  Propagate       = 0;
   Auxiliary       = 0;
   Output          = 0;
+  IC              = 0;
+  Trim            = 0;
 
   terminate = false;
   frozen = false;
   modelLoaded = false;
+  IsSlave = false;
 
+  // Multiple FDM's are stopped for now.  We need to ensure that
+  // the "user" instance always gets the zeroeth instance number,
+  // because there may be instruments or scripts tied to properties
+  // in the jsbsim[0] node.
   IdFDM = FDMctr;
-  FDMctr++;
+  //FDMctr++;
 
   try {
     char* num = getenv("JSBSIM_DEBUG");
-    if (!num) debug_lvl = 1;
-    else debug_lvl = atoi(num); // set debug level
+    if (num) debug_lvl = atoi(num); // set debug level
   } catch (...) {               // if error set to 1
     debug_lvl = 1;
   }
 
+  if (root == 0)  master= new FGPropertyManager;
+  else            master = root;
+
+  instance = master->GetNode("/fdm/jsbsim",IdFDM,true);
+
+
   Debug(0);
 
-  Allocate();
+  // this is here to catch errors in binding member functions
+  // to the property tree.
+  try {
+    Allocate();
+  } catch ( string msg ) {
+    cout << "Caught error: " << msg << endl;
+    exit(1);
+  }
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGFDMExec::~FGFDMExec()
 {
-  DeAllocate();
+  try {
+    DeAllocate();
+    checkTied( instance );
+  } catch ( string msg ) {
+    cout << "Caught error: " << msg << endl;
+  }
+
+  for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec;
+  SlaveFDMList.clear();
 
   Debug(1);
 }
@@ -150,16 +196,15 @@ bool FGFDMExec::Allocate(void)
   Inertial        = new FGInertial(this);
   GroundReactions = new FGGroundReactions(this);
   Aircraft        = new FGAircraft(this);
-  Translation     = new FGTranslation(this);
-  Rotation        = new FGRotation(this);
-  Position        = new FGPosition(this);
+  GroundCallback  = new FGGroundCallback();
+  Propagate       = new FGPropagate(this);
   Auxiliary       = new FGAuxiliary(this);
   Output          = new FGOutput(this);
 
   State        = new FGState(this); // This must be done here, as the FGState
                                     // class needs valid pointers to the above
                                     // model classes
-  
+
   // Initialize models so they can communicate with each other
 
   if (!Atmosphere->InitModel()) {
@@ -186,15 +231,9 @@ bool FGFDMExec::Allocate(void)
   if (!Aircraft->InitModel())   {
     cerr << fgred << "Aircraft model init failed" << fgdef << endl;
     Error+=128;}
-  if (!Translation->InitModel()){
-    cerr << fgred << "Translation model init failed" << fgdef << endl;
-    Error+=256;}
-  if (!Rotation->InitModel())   {
-    cerr << fgred << "Rotation model init failed" << fgdef << endl;
+  if (!Propagate->InitModel())   {
+    cerr << fgred << "Propagate model init failed" << fgdef << endl;
     Error+=512;}
-  if (!Position->InitModel())   {
-    cerr << fgred << "Position model init failed" << fgdef << endl;
-    Error+=1024;}
   if (!Auxiliary->InitModel())  {
     cerr << fgred << "Auxiliary model init failed" << fgdef << endl;
     Error+=2058;}
@@ -204,9 +243,12 @@ bool FGFDMExec::Allocate(void)
 
   if (Error > 0) result = false;
 
+  IC = new FGInitialCondition(this);
+
   // Schedule a model. The second arg (the integer) is the pass number. For
   // instance, the atmosphere model gets executed every fifth pass it is called
   // by the executive. Everything else here gets executed each pass.
+  // IC and Trim objects are NOT scheduled.
 
   Schedule(Atmosphere,      1);
   Schedule(FCS,             1);
@@ -216,9 +258,7 @@ bool FGFDMExec::Allocate(void)
   Schedule(Inertial,        1);
   Schedule(GroundReactions, 1);
   Schedule(Aircraft,        1);
-  Schedule(Rotation,        1);
-  Schedule(Translation,     1);
-  Schedule(Position,        1);
+  Schedule(Propagate,       1);
   Schedule(Auxiliary,       1);
   Schedule(Output,          1);
 
@@ -229,22 +269,25 @@ bool FGFDMExec::Allocate(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-bool FGFDMExec::DeAllocate(void) {
-
-  if ( Atmosphere != 0 )     delete Atmosphere;
-  if ( FCS != 0 )            delete FCS;
-  if ( Propulsion != 0)      delete Propulsion;
-  if ( MassBalance != 0)     delete MassBalance;
-  if ( Aerodynamics != 0)    delete Aerodynamics;
-  if ( Inertial != 0)        delete Inertial;
-  if ( GroundReactions != 0) delete GroundReactions;
-  if ( Aircraft != 0 )       delete Aircraft;
-  if ( Translation != 0 )    delete Translation;
-  if ( Rotation != 0 )       delete Rotation;
-  if ( Position != 0 )       delete Position;
-  if ( Auxiliary != 0 )      delete Auxiliary;
-  if ( Output != 0 )         delete Output;
-  if ( State != 0 )          delete State;
+bool FGFDMExec::DeAllocate(void)
+{
+  delete Atmosphere;
+  delete FCS;
+  delete Propulsion;
+  delete MassBalance;
+  delete Aerodynamics;
+  delete Inertial;
+  delete GroundReactions;
+  delete Aircraft;
+  delete Propagate;
+  delete Auxiliary;
+  delete Output;
+  delete State;
+
+  delete IC;
+  delete Trim;
+
+  delete GroundCallback;
 
   FirstModel  = 0L;
   Error       = 0;
@@ -258,9 +301,7 @@ bool FGFDMExec::DeAllocate(void) {
   Inertial        = 0;
   GroundReactions = 0;
   Aircraft        = 0;
-  Translation     = 0;
-  Rotation        = 0;
-  Position        = 0;
+  Propagate       = 0;
   Auxiliary       = 0;
   Output          = 0;
 
@@ -291,7 +332,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
     model_iterator->NextModel->SetRate(rate);
 
   }
-  
+
   return 0;
 }
 
@@ -308,48 +349,98 @@ bool FGFDMExec::Run(void)
 
   Debug(2);
 
-  while (!model_iterator->Run()) {
+  for (unsigned int i=1; i<SlaveFDMList.size(); i++) {
+//    SlaveFDMList[i]->exec->State->Initialize(); // Transfer state to the slave FDM
+//    SlaveFDMList[i]->exec->Run();
+  }
+
+  while (model_iterator != 0L) {
+    model_iterator->Run();
     model_iterator = model_iterator->NextModel;
-    if (model_iterator == 0L) break;
   }
 
   frame = Frame++;
   State->IncrTime();
-
   return true;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-bool FGFDMExec::RunIC(FGInitialCondition *fgic)
+bool FGFDMExec::RunIC(void)
 {
   State->Suspend();
-  State->Initialize(fgic);
+  State->Initialize(IC);
   Run();
   State->Resume();
+
   return true;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-bool FGFDMExec::LoadModel(string APath, string EPath, string model)
+void FGFDMExec::SetGroundCallback(FGGroundCallback* p) {
+  if (GroundCallback)
+    delete GroundCallback;
+  GroundCallback = p;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+vector <string> FGFDMExec::EnumerateFDMs(void)
+{
+  vector <string> FDMList;
+
+  FDMList.push_back(Aircraft->GetAircraftName());
+
+  for (unsigned int i=1; i<SlaveFDMList.size(); i++) {
+    FDMList.push_back(SlaveFDMList[i]->exec->GetAircraft()->GetAircraftName());
+  }
+
+  return FDMList;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFDMExec::LoadModel(string AircraftPath, string EnginePath, string model,
+                bool addModelToPath)
 {
+
+  FGFDMExec::AircraftPath = AircraftPath;
+  FGFDMExec::EnginePath = EnginePath;
+
+  return LoadModel(model, addModelToPath);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+bool FGFDMExec::LoadModel(string model, bool addModelToPath)
+{
+  
   bool result = true;
   string token;
   string aircraftCfgFileName;
 
-  AircraftPath = APath;
-  EnginePath   = EPath;
+  if( AircraftPath.empty() || EnginePath.empty() ) {
+    cerr << "Error: attempted to load aircraft with undefined ";
+    cerr << "aircraft and engine paths" << endl;
+    return false;
+  }
 
+  aircraftCfgFileName = AircraftPath;
 # ifndef macintosh
-  aircraftCfgFileName = AircraftPath + "/" + model + "/" + model + ".xml";
+  if (addModelToPath) aircraftCfgFileName += "/" + model;
+  aircraftCfgFileName += "/" + model + ".xml";
 # else
-  aircraftCfgFileName = AircraftPath + ";" + model + ";" + model + ".xml";
+  if (addModelToPath) aircraftCfgFileName += ";"  + model;
+  aircraftCfgFileName += ";"  + model + ".xml";
 # endif
 
   FGConfigFile AC_cfg(aircraftCfgFileName);
   if (!AC_cfg.IsOpen()) return false;
 
+  modelName = model;
+
   if (modelLoaded) {
     DeAllocate();
     Allocate();
@@ -362,6 +453,10 @@ bool FGFDMExec::LoadModel(string APath, string EPath, string model)
     if (token == "METRICS") {
       if (debug_lvl > 0) cout << fgcyan << "\n  Reading Metrics" << fgdef << endl;
       if (!ReadMetrics(&AC_cfg)) result = false;
+    } else if (token == "SLAVE") {
+      if (debug_lvl > 0) cout << fgcyan << "\n  Reading Slave flight vehicle: " << fgdef
+                                        << AC_cfg.GetValue("NAME") << endl;
+      if (!ReadSlave(&AC_cfg)) result = false;
     } else if (token == "AERODYNAMICS") {
       if (debug_lvl > 0) cout << fgcyan << "\n  Reading Aerodynamics" << fgdef << endl;
       if (!ReadAerodynamics(&AC_cfg)) result = false;
@@ -374,6 +469,9 @@ bool FGFDMExec::LoadModel(string APath, string EPath, string model)
     } else if (token == "FLIGHT_CONTROL") {
       if (debug_lvl > 0) cout << fgcyan << "\n  Reading Flight Control" << fgdef << endl;
       if (!ReadFlightControls(&AC_cfg)) result = false;
+    } else if (token == "AUTOPILOT") {
+      if (debug_lvl > 0) cout << fgcyan << "\n  Reading Autopilot" << fgdef << endl;
+      if (!ReadFlightControls(&AC_cfg)) result = false;
     } else if (token == "OUTPUT") {
       if (debug_lvl > 0) cout << fgcyan << "\n  Reading Output directives" << fgdef << endl;
       if (!ReadOutput(&AC_cfg)) result = false;
@@ -399,7 +497,7 @@ bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg)
   string token = AC_cfg->GetValue();
   string scratch;
   string AircraftName;
-  
+
   AircraftName = AC_cfg->GetValue("NAME");
   Aircraft->SetAircraftName(AircraftName);
 
@@ -408,10 +506,11 @@ bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg)
   scratch = AC_cfg->GetValue("VERSION").c_str();
 
   CFGVersion = AC_cfg->GetValue("VERSION");
+  Release    = AC_cfg->GetValue("RELEASE");
 
   if (debug_lvl > 0)
     cout << "                            Version: " << highint << CFGVersion
-                                                             << normint << endl;
+                                                    << normint << endl;
   if (CFGVersion != needed_cfg_version) {
     cerr << endl << fgred << "YOU HAVE AN INCOMPATIBLE CFG FILE FOR THIS AIRCRAFT."
             " RESULTS WILL BE UNPREDICTABLE !!" << endl;
@@ -419,6 +518,82 @@ bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg)
     cerr << "         You have version: " << CFGVersion << endl << fgdef << endl;
     return false;
   }
+
+  if (Release == "ALPHA" && debug_lvl > 0) {
+#ifndef _MSC_VER
+    system("banner ALPHA");
+#endif
+    cout << endl << endl
+         << highint << "This aircraft model is an " << fgred << Release
+         << reset << highint << " release!!!" << endl << endl << reset
+         << "This aircraft model may not even properly load, and probably"
+         << " will not fly as expected." << endl << endl
+         << fgred << highint << "Use this model for development purposes ONLY!!!"
+         << normint << reset << endl << endl;
+  } else if (Release == "BETA" && debug_lvl > 0) {
+#ifndef _MSC_VER
+    system("banner BETA");
+#endif
+    cout << endl << endl
+         << highint << "This aircraft model is a " << fgred << Release
+         << reset << highint << " release!!!" << endl << endl << reset
+         << "This aircraft model probably will not fly as expected." << endl << endl
+         << fgblue << highint << "Use this model for development purposes ONLY!!!"
+         << normint << reset << endl << endl;
+  }
+
+  return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFDMExec::ReadSlave(FGConfigFile* AC_cfg)
+{
+  // Add a new slaveData object to the slave FDM list
+  // Populate that slaveData element with a new FDMExec object
+  // Set the IsSlave flag for that FDMExec object
+  // Get the aircraft name
+  // set debug level to print out no additional data for slave objects
+  // Load the model given the aircraft name
+  // reset debug level to prior setting
+
+  int saved_debug_lvl = debug_lvl;
+  string token;
+
+  SlaveFDMList.push_back(new slaveData);
+  SlaveFDMList.back()->exec = new FGFDMExec();
+  SlaveFDMList.back()->exec->SetSlave();
+
+  string AircraftName = AC_cfg->GetValue("FILE");
+
+  debug_lvl = 0;                 // turn off debug output for slave vehicle
+
+  SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath );
+  SlaveFDMList.back()->exec->SetEnginePath( EnginePath );
+  SlaveFDMList.back()->exec->LoadModel(AircraftName);
+  debug_lvl = saved_debug_lvl;   // turn debug output back on for master vehicle
+
+  AC_cfg->GetNextConfigLine();
+  while ((token = AC_cfg->GetValue()) != string("/SLAVE")) {
+    *AC_cfg >> token;
+    if      (token == "XLOC")  { *AC_cfg >> SlaveFDMList.back()->x;    }
+    else if (token == "YLOC")  { *AC_cfg >> SlaveFDMList.back()->y;    }
+    else if (token == "ZLOC")  { *AC_cfg >> SlaveFDMList.back()->z;    }
+    else if (token == "PITCH") { *AC_cfg >> SlaveFDMList.back()->pitch;}
+    else if (token == "YAW")   { *AC_cfg >> SlaveFDMList.back()->yaw;  }
+    else if (token == "ROLL")  { *AC_cfg >> SlaveFDMList.back()->roll;  }
+    else cerr << "Unknown identifier: " << token << " in slave vehicle definition" << endl;
+  }
+
+  if (debug_lvl > 0)  {
+    cout << "      X = " << SlaveFDMList.back()->x << endl;
+    cout << "      Y = " << SlaveFDMList.back()->y << endl;
+    cout << "      Z = " << SlaveFDMList.back()->z << endl;
+    cout << "      Pitch = " << SlaveFDMList.back()->pitch << endl;
+    cout << "      Yaw = " << SlaveFDMList.back()->yaw << endl;
+    cout << "      Roll = " << SlaveFDMList.back()->roll << endl;
+  }
+
   return true;
 }
 
@@ -488,6 +663,20 @@ bool FGFDMExec::ReadOutput(FGConfigFile* AC_cfg)
   return true;
 }
 
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropertyManager* FGFDMExec::GetPropertyManager(void) {
+  return instance;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTrim* FGFDMExec::GetTrim(void) {
+  delete Trim;
+  Trim = new FGTrim(this,tNone);
+  return Trim;
+}
+
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 //    The bitmasked value choices are as follows:
 //    unset: In this case (the default) JSBSim would only print
@@ -511,7 +700,7 @@ void FGFDMExec::Debug(int from)
 {
   if (debug_lvl <= 0) return;
 
-  if (debug_lvl & 1) { // Standard console startup message output
+  if (debug_lvl & 1 && IdFDM == 0) { // Standard console startup message output
     if (from == 0) { // Constructor
       cout << "\n\n     " << highint << underon << "JSBSim Flight Dynamics Model v"
                                      << JSBSim_version << underoff << normint << endl;
@@ -542,4 +731,5 @@ void FGFDMExec::Debug(int from)
     }
   }
 }
+}