42#include "initialization/FGTrim.h"
43#include "initialization/FGInitialCondition.h"
45#include "input_output/FGXMLFileRead.h"
46#include "input_output/string_utilities.h"
48#if !defined(__GNUC__) && !defined(sgi) && !defined(_MSC_VER)
56#elif defined(__GNUC__) && !defined(sgi)
57# define __GNU_VISIBLE 1
61#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
62# define WIN32_LEAN_AND_MEAN
66# include <sys/types.h>
67# include <sys/timeb.h>
73#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 7
74#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
94vector <string> LogOutputName;
95vector <SGPath> LogDirectiveName;
96vector <string> CommandLineProperties;
97vector <double> CommandLinePropertyValues;
107double end_time = 1e99;
108double simulation_rate = 1./120.;
109bool override_sim_rate =
false;
110double sleep_period=0.01;
116bool options(
int,
char**);
117int real_main(
int argc,
char* argv[]);
120#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
121 double getcurrentseconds(
void)
125 return tm_ptr.time + tm_ptr.millitm*0.001;
128 double getcurrentseconds(
void)
133 gettimeofday(&tval, &tz);
134 return (tval.tv_sec + tval.tv_usec*1e-6);
138#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
139 void sim_nsleep(
long nanosec)
141 Sleep((DWORD)(nanosec*1e-6));
144 void sim_nsleep(
long nanosec)
146 struct timespec ts, ts1;
149 ts.tv_nsec = nanosec;
150 nanosleep(&ts, &ts1);
158 bool IsScriptFile(
const SGPath& filename) {
160 Element *document = LoadXMLDocument(filename,
false);
161 if (document && document->
GetName() ==
"runscript") result =
true;
165 bool IsLogDirectiveFile(
const SGPath& filename) {
167 Element *document = LoadXMLDocument(filename,
false);
168 if (document && document->
GetName() ==
"output") result =
true;
172 bool IsAircraftFile(
const SGPath& filename) {
174 Element* document = LoadXMLDocument(filename,
false);
175 if (document && document->
GetName() ==
"fdm_config") result =
true;
179 bool IsInitFile(
const SGPath& filename) {
181 Element *document = LoadXMLDocument(filename,
false);
182 if (document && document->
GetName() ==
"initialize") result =
true;
194 void start(
void) { initial_seconds = getcurrentseconds(); }
199 if (isPaused) pause_start_seconds = initial_seconds;
210 pause_start_seconds = getcurrentseconds();
215 double pause_duration = getcurrentseconds() - pause_start_seconds;
216 initial_seconds += pause_duration;
221 double initial_seconds = 0.0;
222 bool isPaused =
false;
223 double pause_start_seconds = 0.0;
328int main(
int argc,
char* argv[])
330#if defined(_MSC_VER) || defined(__MINGW32__)
332 _controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW),
334#elif defined(__GNUC__) && !defined(sgi) && !defined(__APPLE__)
335 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
339 real_main(argc, argv);
340 }
catch (
string& msg) {
341 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
342 << std::endl <<
"The message was: " << msg << std::endl;
344 }
catch (
const char* msg) {
345 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
346 << std::endl <<
"The message was: " << msg << std::endl;
349 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
350 << std::endl <<
"The message was: " << e.what() << std::endl;
353 std::cerr <<
"FATAL ERROR: JSBSim terminated with an unknown exception."
360int real_main(
int argc,
char* argv[])
368 OutputPath = SGPath(
".");
369 LogOutputName.clear();
370 LogDirectiveName.clear();
371 bool result =
false, success;
372 double frame_duration;
374 double new_five_second_value = 0.0;
375 double actual_elapsed_time = 0;
376 double cycle_duration = 0.0;
377 double override_sim_rate_value = 0.0;
378 long sleep_nseconds = 0;
387 success = options(argc, argv);
400 FDMExec->
GetPropertyManager()->Tie(
"simulation/frame_start_time", &actual_elapsed_time);
404 SGPropertyNode_ptr reset_node = FDMExec->
GetPropertyManager()->GetNode(
"simulation/reset");
405 reset_node->addChangeListener(&timer);
411 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
413 GetConsoleMode(hStdOut, &dwMode);
414 if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
420 if (logger) logger->DisableHighLighting();
423 if (simulation_rate < 1.0 )
424 FDMExec->
Setdt(simulation_rate);
426 FDMExec->
Setdt(1.0/simulation_rate);
428 if (override_sim_rate) override_sim_rate_value = FDMExec->
GetDeltaT();
432 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
434 if (CommandLineProperties[i].find(
"simulation") != std::string::npos) {
436 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
441 if (!PlanetName.isNull()) {
442 result = FDMExec->
LoadPlanet(PlanetName,
false);
445 cerr <<
"Planet file " << PlanetName <<
" was not successfully loaded" << endl;
452 if (!ScriptName.isNull()) {
454 result = FDMExec->
LoadScript(ScriptName, override_sim_rate_value, ResetName);
457 cerr <<
"Script file " << ScriptName <<
" was not successfully loaded" << endl;
463 }
else if (!AircraftName.empty() || !ResetName.isNull()) {
467 if ( ! FDMExec->
LoadModel(SGPath(
"aircraft"),
471 cerr <<
" JSBSim could not be started" << endl << endl;
477 FDMExec->PrintPropertyCatalog();
482 auto IC = FDMExec->
GetIC();
483 if ( ! IC->Load(ResetName)) {
485 cerr <<
"Initialization unsuccessful" << endl;
490 cout <<
" No Aircraft, Script, or Reset information given" << endl << endl;
496 for (
unsigned int i=0; i<LogDirectiveName.size(); i++) {
497 if (!LogDirectiveName[i].isNull()) {
499 cout <<
"Output directives not properly set in file " << LogDirectiveName[i] << endl;
510 for (
unsigned int i=0; i<LogOutputName.size(); i++) {
513 cout <<
"Output filename could not be set" << endl;
515 cout <<
"Output filename change from " << old_filename <<
" from aircraft"
516 " configuration file to " << LogOutputName[i] <<
" specified on"
517 " command line" << endl;
523 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
526 cerr << endl <<
" No property by the name " << CommandLineProperties[i] << endl;
530 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
537 FDMExec->PrintSimulationConfiguration();
543 JSBSim::TrimMode icTrimRequested = (JSBSim::TrimMode)FDMExec->
GetIC()->TrimRequested();
544 if (icTrimRequested != JSBSim::TrimMode::tNone) {
553 }
catch (
string& msg) {
554 cerr << endl << msg << endl << endl;
562 out << endl << JSBSim::LogFormat::GREEN << JSBSim::LogFormat::BOLD
563 <<
"---- JSBSim Execution beginning ... --------------------------------------------"
564 << JSBSim::LogFormat::RESET << endl << endl;
567 result = FDMExec->
Run();
569 if (suspend) FDMExec->
Hold();
576#if defined(_MSC_VER) || defined(__MINGW32__)
577 localtime_s(&local, &tod);
579 localtime_r(&tod, &local);
581 strftime(s, 99,
"%A %B %d %Y %X", &local);
582 cout <<
"Start: " << s <<
" (HH:MM:SS)" << endl;
585 if (realtime) sleep_nseconds = (long)(frame_duration*1e9);
586 else sleep_nseconds = (sleep_period )*1e9;
592 while (result && FDMExec->
GetSimTime() <= end_time) {
604 result = FDMExec->
Run();
606 if (play_nice) sim_nsleep(sleep_nseconds);
612 double sim_lag_time = actual_elapsed_time - FDMExec->
GetSimTime();
613 double cycle_start = getcurrentseconds();
615 for (
int i=0; i<(int)(sim_lag_time/frame_duration); i++) {
616 result = FDMExec->
Run();
617 cycle_duration = getcurrentseconds() - cycle_start;
618 cycle_start = getcurrentseconds();
622 if (play_nice) sim_nsleep(sleep_nseconds);
624 if (FDMExec->
GetSimTime() >= new_five_second_value) {
625 cout <<
"Simulation elapsed time: " << FDMExec->
GetSimTime() << endl;
626 new_five_second_value += 5.0;
631 sim_nsleep(sleep_nseconds);
632 result = FDMExec->
Run();
639#if defined(_MSC_VER) || defined(__MINGW32__)
640 localtime_s(&local, &tod);
642 localtime_r(&tod, &local);
644 strftime(s, 99,
"%A %B %d %Y %X", &local);
645 cout <<
"End: " << s <<
" (HH:MM:SS)" << endl;
655#define gripe cerr << "Option '" << keyword \
656 << "' requires a value, as in '" \
657 << keyword << "=something'" << endl << endl;
659bool options(
int count,
char **arg)
669 cout.setf(ios_base::fixed);
671 for (i=1; i<count; i++) {
672 string argument = string(arg[i]);
673 string keyword(argument);
675 string::size_type n=argument.find(
"=");
677 if (n != string::npos && n > 0) {
678 keyword = argument.substr(0, n);
679 value = argument.substr(n+1);
682 if (keyword ==
"--help") {
685 }
else if (keyword ==
"--version") {
686 cout << endl <<
" JSBSim Version: " << FDMExec->
GetVersion() << endl << endl;
688 }
else if (keyword ==
"--realtime") {
690 }
else if (keyword ==
"--nice") {
692 if (n != string::npos) {
694 sleep_period = JSBSim::atof_locale_c( value.c_str() );
696 cerr << endl <<
" Invalid sleep period given!" << endl << endl;
702 }
else if (keyword ==
"--suspend") {
704 }
else if (keyword ==
"--nohighlight") {
706 }
else if (keyword ==
"--outputlogfile") {
707 if (n != string::npos) {
708 LogOutputName.push_back(value);
710 }
else if (keyword ==
"--logdirectivefile") {
711 if (n != string::npos) {
712 LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
717 }
else if (keyword ==
"--root") {
718 if (n != string::npos) {
719 RootDir = SGPath::fromLocal8Bit(value.c_str());
724 }
else if (keyword ==
"--outputpath") {
725 if (n != string::npos) {
726 OutputPath = SGPath::fromLocal8Bit(value.c_str());
731 }
else if (keyword ==
"--aircraft") {
732 if (n != string::npos) {
733 AircraftName = value;
738 }
else if (keyword ==
"--script") {
739 if (n != string::npos) {
740 ScriptName = SGPath::fromLocal8Bit(value.c_str());
745 }
else if (keyword ==
"--initfile") {
746 if (n != string::npos) {
747 ResetName = SGPath::fromLocal8Bit(value.c_str());
752 }
else if (keyword ==
"--planet") {
753 if (n != string::npos) {
754 PlanetName = SGPath::fromLocal8Bit(value.c_str());
759 }
else if (keyword ==
"--property") {
760 if (n != string::npos) {
761 string propName = value.substr(0,value.find(
"="));
762 string propValueString = value.substr(value.find(
"=")+1);
765 propValue = JSBSim::atof_locale_c(propValueString.c_str());
770 CommandLineProperties.push_back(propName);
771 CommandLinePropertyValues.push_back(propValue);
777 }
else if (keyword.substr(0,5) ==
"--end") {
778 if (n != string::npos) {
780 end_time = JSBSim::atof_locale_c( value.c_str() );
782 cerr << endl <<
" Invalid end time given!" << endl << endl;
790 }
else if (keyword ==
"--simulation-rate") {
791 if (n != string::npos) {
793 simulation_rate = JSBSim::atof_locale_c( value.c_str() );
794 override_sim_rate =
true;
796 cerr << endl <<
" Invalid simulation rate given!" << endl << endl;
804 }
else if (keyword ==
"--catalog") {
806 if (!value.empty()) AircraftName=value;
807 }
else if (keyword.substr(0,2) !=
"--" && value.empty() ) {
811 SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
813 if (xmlFile.IsScriptFile(path)) ScriptName = path;
814 else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
815 else if (xmlFile.IsAircraftFile(SGPath(
"aircraft")/keyword/keyword)) AircraftName = keyword;
816 else if (xmlFile.IsInitFile(path)) ResetName = path;
817 else if (xmlFile.IsInitFile(SGPath(
"aircraft")/AircraftName/keyword)) ResetName = SGPath(
"aircraft")/AircraftName/keyword;
819 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
827 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
835 if (catalog && !ScriptName.isNull()) {
836 cerr <<
"Cannot specify catalog with script option" << endl << endl;
839 if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
840 cerr <<
"You must specify an initialization file with the aircraft name." << endl << endl;
843 if (!ScriptName.isNull() && !AircraftName.empty()) {
844 cerr <<
"You cannot specify an aircraft file with a script." << endl;
856 cout << endl <<
" JSBSim version " << FDMExec->
GetVersion() << endl << endl;
857 cout <<
" Usage: jsbsim [script file name] [output file names] <options>" << endl << endl;
858 cout <<
" options:" << endl;
859 cout <<
" --help returns this message" << endl;
860 cout <<
" --version returns the version number" << endl;
861 cout <<
" --root=<path> specifies the JSBSim root directory (where aircraft/, engine/, etc. reside)" << endl;
862 cout <<
" --aircraft=<filename> specifies the name of the aircraft to be modeled" << endl;
863 cout <<
" --script=<filename> specifies a script to run" << endl;
864 cout <<
" --initfile=<filename> specifies an initialization file" << endl;
865 cout <<
" --planet=<filename> specifies a planet definition file" << endl;
866 cout <<
" --outputlogfile=<filename> sets (overrides) the name of a data output file" << endl;
867 cout <<
" --logdirectivefile=<filename> specifies the name of a data logging directives file" << endl;
868 cout <<
" (can appear multiple times)" << endl;
869 cout <<
" --outputpath=<path> specifies the directory where the output files will be written." << endl;
870 cout <<
" --realtime specifies to run in actual real world time" << endl;
871 cout <<
" --nice specifies to run at lower CPU usage" << endl;
872 cout <<
" --nohighlight specifies that console output should be pure text only (no color)" << endl;
873 cout <<
" --suspend specifies to suspend the simulation after initialization" << endl;
874 cout <<
" --catalog specifies that all properties for this aircraft model should be printed" << endl;
875 cout <<
" (catalog=aircraftname is an optional format)" << endl;
876 cout <<
" --property=<name=value> e.g. --property=simulation/integrator/rate/rotational=1" << endl;
877 cout <<
" --simulation-rate=<rate (double)> specifies the sim dT time or frequency" << endl;
878 cout <<
" If rate specified is less than 1, it is interpreted as" << endl;
879 cout <<
" a time step size, otherwise it is assumed to be a rate in Hertz." << endl;
880 cout <<
" --end=<time (double)> specifies the sim end time" << endl << endl;
882 cout <<
" NOTE: There can be no spaces around the = sign when" << endl;
883 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.
void SetPropertyValue(const std::string &property, double value)
Sets a property value.
std::shared_ptr< FGInitialCondition > GetIC(void) const
Returns a pointer to the FGInitialCondition object.
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.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
void Hold(void)
Pauses execution by preventing time from incrementing.
bool SetAircraftPath(const SGPath &path)
Set the path to the aircraft config file directories.
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 const std::string & GetVersion(void)
Returns the version number of JSBSim.
The trimming routine for JSBSim.
void Report(void)
Print the results of the trim.
bool DoTrim(void)
Execute the trim.
The property change listener interface.
A node in a property tree.
The Timer class measures the elapsed real time and can be paused and resumed.
void pause(bool paused)
Pause the timer if the paused parameter is true and resume it if the paused parameter is false.
void valueChanged(SGPropertyNode *prop) override
Restart the timer when the listened property is modified.
double getElapsedTime(void)
Get the elapsed real time in seconds since the timer was started.
This class is solely for the purpose of determining what type of file is given on the command line.
FGLogger_ptr GetLogger(void)
Returns the active logger for the current thread.