42 #include "initialization/FGTrim.h"
43 #include "initialization/FGInitialCondition.h"
44 #include "FGFDMExec.h"
45 #include "input_output/FGXMLFileRead.h"
47 #if !defined(__GNUC__) && !defined(sgi) && !defined(_MSC_VER)
55 #elif defined(__GNUC__) && !defined(sgi)
56 # define __GNU_VISIBLE 1
60 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
61 # define WIN32_LEAN_AND_MEAN
63 # include <mmsystem.h>
65 # include <sys/types.h>
66 # include <sys/timeb.h>
68 # include <sys/time.h>
87 vector <string> LogOutputName;
88 vector <SGPath> LogDirectiveName;
89 vector <string> CommandLineProperties;
90 vector <double> CommandLinePropertyValues;
100 double end_time = 1e99;
101 double simulation_rate = 1./120.;
102 bool override_sim_rate =
false;
103 double sleep_period=0.01;
109 bool options(
int,
char**);
110 int real_main(
int argc,
char* argv[]);
111 void PrintHelp(
void);
113 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
114 double getcurrentseconds(
void)
118 return tm_ptr.time + tm_ptr.millitm*0.001;
121 double getcurrentseconds(
void)
126 gettimeofday(&tval, &tz);
127 return (tval.tv_sec + tval.tv_usec*1e-6);
131 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
132 void sim_nsleep(
long nanosec)
134 Sleep((DWORD)(nanosec*1e-6));
137 void sim_nsleep(
long nanosec)
139 struct timespec ts, ts1;
142 ts.tv_nsec = nanosec;
143 nanosleep(&ts, &ts1);
151 bool IsScriptFile(
const SGPath& filename) {
153 Element *document = LoadXMLDocument(filename,
false);
154 if (document && document->
GetName() ==
"runscript") result =
true;
158 bool IsLogDirectiveFile(
const SGPath& filename) {
160 Element *document = LoadXMLDocument(filename,
false);
161 if (document && document->
GetName() ==
"output") result =
true;
165 bool IsAircraftFile(
const SGPath& filename) {
167 Element* document = LoadXMLDocument(filename,
false);
168 if (document && document->
GetName() ==
"fdm_config") result =
true;
172 bool IsInitFile(
const SGPath& filename) {
174 Element *document = LoadXMLDocument(filename,
false);
175 if (document && document->
GetName() ==
"initialize") result =
true;
283 int main(
int argc,
char* argv[])
285 #if defined(_MSC_VER) || defined(__MINGW32__)
287 _controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW),
289 #elif defined(__GNUC__) && !defined(sgi) && !defined(__APPLE__)
290 feenableexcept(FE_DIVBYZERO | FE_INVALID);
294 real_main(argc, argv);
295 }
catch (
string& msg) {
296 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
297 << std::endl <<
"The message was: " << msg << std::endl;
299 }
catch (
const char* msg) {
300 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
301 << std::endl <<
"The message was: " << msg << std::endl;
304 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
305 << std::endl <<
"The message was: " << e.what() << std::endl;
308 std::cerr <<
"FATAL ERROR: JSBSim terminated with an unknown exception."
315 int real_main(
int argc,
char* argv[])
323 LogOutputName.clear();
324 LogDirectiveName.clear();
325 bool result =
false, success;
326 bool was_paused =
false;
328 double frame_duration;
330 double new_five_second_value = 0.0;
331 double actual_elapsed_time = 0;
332 double initial_seconds = 0;
333 double current_seconds = 0.0;
334 double paused_seconds = 0.0;
335 double sim_lag_time = 0;
336 double cycle_duration = 0.0;
337 double override_sim_rate_value = 0.0;
338 long sleep_nseconds = 0;
347 success = options(argc, argv);
360 FDMExec->
GetPropertyManager()->Tie(
"simulation/frame_start_time", &actual_elapsed_time);
365 if (simulation_rate < 1.0 )
366 FDMExec->
Setdt(simulation_rate);
368 FDMExec->
Setdt(1.0/simulation_rate);
370 if (override_sim_rate) override_sim_rate_value = FDMExec->
GetDeltaT();
374 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
376 if (CommandLineProperties[i].find(
"simulation") != std::string::npos) {
378 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
383 if (!PlanetName.isNull()) {
384 result = FDMExec->
LoadPlanet(PlanetName,
false);
387 cerr <<
"Planet file " << PlanetName <<
" was not successfully loaded" << endl;
394 if (!ScriptName.isNull()) {
396 result = FDMExec->
LoadScript(ScriptName, override_sim_rate_value, ResetName);
399 cerr <<
"Script file " << ScriptName <<
" was not successfully loaded" << endl;
405 }
else if (!AircraftName.empty() || !ResetName.isNull()) {
409 if ( ! FDMExec->
LoadModel(SGPath(
"aircraft"),
413 cerr <<
" JSBSim could not be started" << endl << endl;
419 FDMExec->PrintPropertyCatalog();
424 auto IC = FDMExec->
GetIC();
425 if ( ! IC->Load(ResetName)) {
427 cerr <<
"Initialization unsuccessful" << endl;
432 cout <<
" No Aircraft, Script, or Reset information given" << endl << endl;
438 for (
unsigned int i=0; i<LogDirectiveName.size(); i++) {
439 if (!LogDirectiveName[i].isNull()) {
441 cout <<
"Output directives not properly set in file " << LogDirectiveName[i] << endl;
452 for (
unsigned int i=0; i<LogOutputName.size(); i++) {
455 cout <<
"Output filename could not be set" << endl;
457 cout <<
"Output filename change from " << old_filename <<
" from aircraft"
458 " configuration file to " << LogOutputName[i] <<
" specified on"
459 " command line" << endl;
465 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
468 cerr << endl <<
" No property by the name " << CommandLineProperties[i] << endl;
472 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
479 FDMExec->PrintSimulationConfiguration();
485 JSBSim::TrimMode icTrimRequested = (JSBSim::TrimMode)FDMExec->
GetIC()->TrimRequested();
486 if (icTrimRequested != JSBSim::TrimMode::tNone) {
495 }
catch (
string& msg) {
496 cerr << endl << msg << endl << endl;
502 <<
"---- JSBSim Execution beginning ... --------------------------------------------"
505 result = FDMExec->
Run();
507 if (suspend) FDMExec->
Hold();
514 #if defined(_MSC_VER) || defined(__MINGW32__)
515 localtime_s(&local, &tod);
517 localtime_r(&tod, &local);
519 strftime(s, 99,
"%A %B %d %Y %X", &local);
520 cout <<
"Start: " << s <<
" (HH:MM:SS)" << endl;
523 if (realtime) sleep_nseconds = (long)(frame_duration*1e9);
524 else sleep_nseconds = (sleep_period )*1e9;
527 current_seconds = initial_seconds = getcurrentseconds();
530 while (result && FDMExec->
GetSimTime() <= end_time) {
542 result = FDMExec->
Run();
544 if (play_nice) sim_nsleep(sleep_nseconds);
550 initial_seconds += paused_seconds;
553 current_seconds = getcurrentseconds();
554 actual_elapsed_time = current_seconds - initial_seconds;
555 sim_lag_time = actual_elapsed_time - FDMExec->
GetSimTime();
557 for (
int i=0; i<(int)(sim_lag_time/frame_duration); i++) {
558 result = FDMExec->
Run();
559 cycle_duration = getcurrentseconds() - current_seconds;
560 current_seconds = getcurrentseconds();
564 if (play_nice) sim_nsleep(sleep_nseconds);
566 if (FDMExec->
GetSimTime() >= new_five_second_value) {
567 cout <<
"Simulation elapsed time: " << FDMExec->
GetSimTime() << endl;
568 new_five_second_value += 5.0;
573 paused_seconds = getcurrentseconds() - current_seconds;
574 sim_nsleep(sleep_nseconds);
575 result = FDMExec->
Run();
582 #if defined(_MSC_VER) || defined(__MINGW32__)
583 localtime_s(&local, &tod);
585 localtime_r(&tod, &local);
587 strftime(s, 99,
"%A %B %d %Y %X", &local);
588 cout <<
"End: " << s <<
" (HH:MM:SS)" << endl;
598 #define gripe cerr << "Option '" << keyword \
599 << "' requires a value, as in '" \
600 << keyword << "=something'" << endl << endl;
602 bool options(
int count,
char **arg)
612 cout.setf(ios_base::fixed);
614 for (i=1; i<count; i++) {
615 string argument = string(arg[i]);
616 string keyword(argument);
618 string::size_type n=argument.find(
"=");
620 if (n != string::npos && n > 0) {
621 keyword = argument.substr(0, n);
622 value = argument.substr(n+1);
625 if (keyword ==
"--help") {
628 }
else if (keyword ==
"--version") {
629 cout << endl <<
" JSBSim Version: " << FDMExec->
GetVersion() << endl << endl;
631 }
else if (keyword ==
"--realtime") {
633 }
else if (keyword ==
"--nice") {
635 if (n != string::npos) {
637 sleep_period = atof( value.c_str() );
639 cerr << endl <<
" Invalid sleep period given!" << endl << endl;
645 }
else if (keyword ==
"--suspend") {
647 }
else if (keyword ==
"--nohighlight") {
649 }
else if (keyword ==
"--outputlogfile") {
650 if (n != string::npos) {
651 LogOutputName.push_back(value);
653 }
else if (keyword ==
"--logdirectivefile") {
654 if (n != string::npos) {
655 LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
660 }
else if (keyword ==
"--root") {
661 if (n != string::npos) {
662 RootDir = SGPath::fromLocal8Bit(value.c_str());
667 }
else if (keyword ==
"--aircraft") {
668 if (n != string::npos) {
669 AircraftName = value;
674 }
else if (keyword ==
"--script") {
675 if (n != string::npos) {
676 ScriptName = SGPath::fromLocal8Bit(value.c_str());
681 }
else if (keyword ==
"--initfile") {
682 if (n != string::npos) {
683 ResetName = SGPath::fromLocal8Bit(value.c_str());
688 }
else if (keyword ==
"--planet") {
689 if (n != string::npos) {
690 PlanetName = SGPath::fromLocal8Bit(value.c_str());
695 }
else if (keyword ==
"--property") {
696 if (n != string::npos) {
697 string propName = value.substr(0,value.find(
"="));
698 string propValueString = value.substr(value.find(
"=")+1);
699 double propValue = atof(propValueString.c_str());
700 CommandLineProperties.push_back(propName);
701 CommandLinePropertyValues.push_back(propValue);
707 }
else if (keyword.substr(0,5) ==
"--end") {
708 if (n != string::npos) {
710 end_time = atof( value.c_str() );
712 cerr << endl <<
" Invalid end time given!" << endl << endl;
720 }
else if (keyword ==
"--simulation-rate") {
721 if (n != string::npos) {
723 simulation_rate = atof( value.c_str() );
724 override_sim_rate =
true;
726 cerr << endl <<
" Invalid simulation rate given!" << endl << endl;
734 }
else if (keyword ==
"--catalog") {
736 if (!value.empty()) AircraftName=value;
737 }
else if (keyword.substr(0,2) !=
"--" && value.empty() ) {
741 SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
743 if (xmlFile.IsScriptFile(path)) ScriptName = path;
744 else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
745 else if (xmlFile.IsAircraftFile(SGPath(
"aircraft")/keyword/keyword)) AircraftName = keyword;
746 else if (xmlFile.IsInitFile(path)) ResetName = path;
747 else if (xmlFile.IsInitFile(SGPath(
"aircraft")/AircraftName/keyword)) ResetName = SGPath(
"aircraft")/AircraftName/keyword;
749 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
757 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
765 if (catalog && !ScriptName.isNull()) {
766 cerr <<
"Cannot specify catalog with script option" << endl << endl;
769 if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
770 cerr <<
"You must specify an initialization file with the aircraft name." << endl << endl;
773 if (!ScriptName.isNull() && !AircraftName.empty()) {
774 cerr <<
"You cannot specify an aircraft file with a script." << endl;
786 cout << endl <<
" JSBSim version " << FDMExec->
GetVersion() << endl << endl;
787 cout <<
" Usage: jsbsim [script file name] [output file names] <options>" << endl << endl;
788 cout <<
" options:" << endl;
789 cout <<
" --help returns this message" << endl;
790 cout <<
" --version returns the version number" << endl;
791 cout <<
" --outputlogfile=<filename> sets (overrides) the name of a data output file" << endl;
792 cout <<
" --logdirectivefile=<filename> specifies the name of a data logging directives file" << endl;
793 cout <<
" (can appear multiple times)" << endl;
794 cout <<
" --root=<path> specifies the JSBSim root directory (where aircraft/, engine/, etc. reside)" << endl;
795 cout <<
" --aircraft=<filename> specifies the name of the aircraft to be modeled" << endl;
796 cout <<
" --script=<filename> specifies a script to run" << endl;
797 cout <<
" --realtime specifies to run in actual real world time" << endl;
798 cout <<
" --nice specifies to run at lower CPU usage" << endl;
799 cout <<
" --nohighlight specifies that console output should be pure text only (no color)" << endl;
800 cout <<
" --suspend specifies to suspend the simulation after initialization" << endl;
801 cout <<
" --initfile=<filename> specifies an initialization file" << endl;
802 cout <<
" --planet=<filename> specifies a planet definition file" << endl;
803 cout <<
" --catalog specifies that all properties for this aircraft model should be printed" << endl;
804 cout <<
" (catalog=aircraftname is an optional format)" << endl;
805 cout <<
" --property=<name=value> e.g. --property=simulation/integrator/rate/rotational=1" << endl;
806 cout <<
" --simulation-rate=<rate (double)> specifies the sim dT time or frequency" << endl;
807 cout <<
" If rate specified is less than 1, it is interpreted as" << endl;
808 cout <<
" a time step size, otherwise it is assumed to be a rate in Hertz." << endl;
809 cout <<
" --end=<time (double)> specifies the sim end time" << endl << endl;
811 cout <<
" NOTE: There can be no spaces around the = sign when" << endl;
812 cout <<
" an option is followed by a filename" << endl << endl;
const std::string & GetName(void) const
Retrieves the element name.
Encapsulates the JSBSim simulation executive.
std::shared_ptr< FGInitialCondition > GetIC(void) const
Returns a pointer to the FGInitialCondition object.
void SetPropertyValue(const std::string &property, double value)
Sets a property value.
bool SetSystemsPath(const SGPath &path)
Set the path to the systems config file directories.
bool SetOutputFileName(const int n, const std::string &fname)
Sets (or overrides) the output filename.
void SetDebugLevel(int level)
Sets the debug level.
bool LoadScript(const SGPath &Script, double deltaT=0.0, const SGPath &initfile=SGPath())
Load a script.
bool SetEnginePath(const SGPath &path)
Set the path to the engine config file directories.
int GetDebugLevel(void) const
Retrieves the current debug level setting.
bool SetOutputPath(const SGPath &path)
Set the directory where the output files will be written.
void SetRootDir(const SGPath &rootDir)
Set the root directory that is used to obtain absolute paths from relative paths.
std::string GetOutputFileName(int n) const
Retrieves the current output filename.
double GetDeltaT(void) const
Returns the simulation delta T.
std::shared_ptr< FGPropagate > GetPropagate(void) const
Returns the FGPropagate pointer.
void CheckIncrementalHold(void)
Checks if required to hold afer increment.
bool LoadPlanet(const SGPath &PlanetPath, bool useAircraftPath=true)
Loads the planet.
bool Run(void)
This function executes each scheduled model in succession.
bool LoadModel(const SGPath &AircraftPath, const SGPath &EnginePath, const SGPath &SystemsPath, const std::string &model, bool addModelToPath=true)
Loads an aircraft model.
bool SetOutputDirectives(const SGPath &fname)
Sets the output (logging) mechanism for this run.
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
void Setdt(double delta_t)
Sets the integration time step for the simulation executive.
void Hold(void)
Pauses execution by preventing time from incrementing.
bool SetAircraftPath(const SGPath &path)
Set the path to the aircraft config file directories.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
bool RunIC(void)
Initializes the sim from the initial condition object and executes each scheduled model without integ...
bool Holding(void)
Returns true if the simulation is Holding (i.e. simulation time is not moving).
static char fggreen[6]
green text
void disableHighLighting(void)
Disables highlighting in the console output.
static const std::string & GetVersion(void)
Returns the version number of JSBSim.
static char reset[5]
resets text properties
static char highint[5]
highlights text
The trimming routine for JSBSim.
void Report(void)
Print the results of the trim.
bool DoTrim(void)
Execute the trim.
This class is solely for the purpose of determining what type of file is given on the command line.