42 #include "initialization/FGTrim.h"
43 #include "FGFDMExec.h"
44 #include "input_output/FGXMLFileRead.h"
46 #if !defined(__GNUC__) && !defined(sgi) && !defined(_MSC_VER)
54 #elif defined(__GNUC__) && !defined(sgi)
55 # define __GNU_VISIBLE 1
59 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
60 # define WIN32_LEAN_AND_MEAN
62 # include <mmsystem.h>
64 # include <sys/types.h>
65 # include <sys/timeb.h>
67 # include <sys/time.h>
85 vector <string> LogOutputName;
86 vector <SGPath> LogDirectiveName;
87 vector <string> CommandLineProperties;
88 vector <double> CommandLinePropertyValues;
98 double end_time = 1e99;
99 double simulation_rate = 1./120.;
100 bool override_sim_rate =
false;
101 double sleep_period=0.01;
107 bool options(
int,
char**);
108 int real_main(
int argc,
char* argv[]);
109 void PrintHelp(
void);
111 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
112 double getcurrentseconds(
void)
116 return tm_ptr.time + tm_ptr.millitm*0.001;
119 double getcurrentseconds(
void)
124 gettimeofday(&tval, &tz);
125 return (tval.tv_sec + tval.tv_usec*1e-6);
129 #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
130 void sim_nsleep(
long nanosec)
132 Sleep((DWORD)(nanosec*1e-6));
135 void sim_nsleep(
long nanosec)
137 struct timespec ts, ts1;
140 ts.tv_nsec = nanosec;
141 nanosleep(&ts, &ts1);
149 bool IsScriptFile(
const SGPath& filename) {
151 Element *document = LoadXMLDocument(filename,
false);
152 if (document && document->
GetName() ==
"runscript") result =
true;
156 bool IsLogDirectiveFile(
const SGPath& filename) {
158 Element *document = LoadXMLDocument(filename,
false);
159 if (document && document->
GetName() ==
"output") result =
true;
163 bool IsAircraftFile(
const SGPath& filename) {
165 Element* document = LoadXMLDocument(filename,
false);
166 if (document && document->
GetName() ==
"fdm_config") result =
true;
170 bool IsInitFile(
const SGPath& filename) {
172 Element *document = LoadXMLDocument(filename,
false);
173 if (document && document->
GetName() ==
"initialize") result =
true;
281 int main(
int argc,
char* argv[])
283 #if defined(_MSC_VER) || defined(__MINGW32__)
285 _controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW),
287 #elif defined(__GNUC__) && !defined(sgi) && !defined(__APPLE__)
288 feenableexcept(FE_DIVBYZERO | FE_INVALID);
292 real_main(argc, argv);
293 }
catch (
string& msg) {
294 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
295 << std::endl <<
"The message was: " << msg << std::endl;
297 }
catch (
const char* msg) {
298 std::cerr <<
"FATAL ERROR: JSBSim terminated with an exception."
299 << std::endl <<
"The message was: " << msg << std::endl;
302 std::cerr <<
"FATAL ERROR: JSBSim terminated with an unknown exception."
309 int real_main(
int argc,
char* argv[])
316 LogOutputName.clear();
317 LogDirectiveName.clear();
318 bool result =
false, success;
319 bool was_paused =
false;
321 double frame_duration;
323 double new_five_second_value = 0.0;
324 double actual_elapsed_time = 0;
325 double initial_seconds = 0;
326 double current_seconds = 0.0;
327 double paused_seconds = 0.0;
328 double sim_lag_time = 0;
329 double cycle_duration = 0.0;
330 double override_sim_rate_value = 0.0;
331 long sleep_nseconds = 0;
340 success = options(argc, argv);
358 if (simulation_rate < 1.0 )
359 FDMExec->
Setdt(simulation_rate);
361 FDMExec->
Setdt(1.0/simulation_rate);
363 if (override_sim_rate) override_sim_rate_value = FDMExec->
GetDeltaT();
367 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
369 if (CommandLineProperties[i].find(
"simulation") != std::string::npos) {
371 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
377 if (!ScriptName.isNull()) {
379 result = FDMExec->
LoadScript(ScriptName, override_sim_rate_value, ResetName);
382 cerr <<
"Script file " << ScriptName <<
" was not successfully loaded" << endl;
388 }
else if (!AircraftName.empty() || !ResetName.isNull()) {
392 if ( ! FDMExec->
LoadModel(SGPath(
"aircraft"),
396 cerr <<
" JSBSim could not be started" << endl << endl;
402 FDMExec->PrintPropertyCatalog();
408 if ( ! IC->
Load(ResetName)) {
410 cerr <<
"Initialization unsuccessful" << endl;
415 cout <<
" No Aircraft, Script, or Reset information given" << endl << endl;
421 for (
unsigned int i=0; i<LogDirectiveName.size(); i++) {
422 if (!LogDirectiveName[i].isNull()) {
424 cout <<
"Output directives not properly set in file " << LogDirectiveName[i] << endl;
435 for (
unsigned int i=0; i<LogOutputName.size(); i++) {
438 cout <<
"Output filename could not be set" << endl;
440 cout <<
"Output filename change from " << old_filename <<
" from aircraft"
441 " configuration file to " << LogOutputName[i] <<
" specified on"
442 " command line" << endl;
448 for (
unsigned int i=0; i<CommandLineProperties.size(); i++) {
451 cerr << endl <<
" No property by the name " << CommandLineProperties[i] << endl;
455 FDMExec->
SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
462 FDMExec->PrintSimulationConfiguration();
468 JSBSim::TrimMode icTrimRequested = (JSBSim::TrimMode)FDMExec->
GetIC()->
TrimRequested();
469 if (icTrimRequested != JSBSim::TrimMode::tNone) {
478 }
catch (
string& msg) {
479 cerr << endl << msg << endl << endl;
485 <<
"---- JSBSim Execution beginning ... --------------------------------------------"
488 result = FDMExec->
Run();
490 if (suspend) FDMExec->
Hold();
497 #if defined(_MSC_VER) || defined(__MINGW32__)
498 localtime_s(&local, &tod);
500 localtime_r(&tod, &local);
502 strftime(s, 99,
"%A %B %d %Y %X", &local);
503 cout <<
"Start: " << s <<
" (HH:MM:SS)" << endl;
506 if (realtime) sleep_nseconds = (long)(frame_duration*1e9);
507 else sleep_nseconds = (sleep_period )*1e9;
510 current_seconds = initial_seconds = getcurrentseconds();
513 while (result && FDMExec->
GetSimTime() <= end_time) {
528 result = FDMExec->
Run();
530 if (play_nice) sim_nsleep(sleep_nseconds);
536 initial_seconds += paused_seconds;
539 current_seconds = getcurrentseconds();
540 actual_elapsed_time = current_seconds - initial_seconds;
541 sim_lag_time = actual_elapsed_time - FDMExec->
GetSimTime();
543 for (
int i=0; i<(int)(sim_lag_time/frame_duration); i++) {
544 result = FDMExec->
Run();
545 cycle_duration = getcurrentseconds() - current_seconds;
546 current_seconds = getcurrentseconds();
550 if (play_nice) sim_nsleep(sleep_nseconds);
552 if (FDMExec->
GetSimTime() >= new_five_second_value) {
553 cout <<
"Simulation elapsed time: " << FDMExec->
GetSimTime() << endl;
554 new_five_second_value += 5.0;
559 paused_seconds = getcurrentseconds() - current_seconds;
560 sim_nsleep(sleep_nseconds);
561 result = FDMExec->
Run();
568 #if defined(_MSC_VER) || defined(__MINGW32__)
569 localtime_s(&local, &tod);
571 localtime_r(&tod, &local);
573 strftime(s, 99,
"%A %B %d %Y %X", &local);
574 cout <<
"End: " << s <<
" (HH:MM:SS)" << endl;
584 #define gripe cerr << "Option '" << keyword \
585 << "' requires a value, as in '" \
586 << keyword << "=something'" << endl << endl;
588 bool options(
int count,
char **arg)
598 cout.setf(ios_base::fixed);
600 for (i=1; i<count; i++) {
601 string argument = string(arg[i]);
602 string keyword(argument);
604 string::size_type n=argument.find(
"=");
606 if (n != string::npos && n > 0) {
607 keyword = argument.substr(0, n);
608 value = argument.substr(n+1);
611 if (keyword ==
"--help") {
614 }
else if (keyword ==
"--version") {
615 cout << endl <<
" JSBSim Version: " << FDMExec->
GetVersion() << endl << endl;
617 }
else if (keyword ==
"--realtime") {
619 }
else if (keyword ==
"--nice") {
621 if (n != string::npos) {
623 sleep_period = atof( value.c_str() );
625 cerr << endl <<
" Invalid sleep period given!" << endl << endl;
631 }
else if (keyword ==
"--suspend") {
633 }
else if (keyword ==
"--nohighlight") {
635 }
else if (keyword ==
"--outputlogfile") {
636 if (n != string::npos) {
637 LogOutputName.push_back(value);
639 }
else if (keyword ==
"--logdirectivefile") {
640 if (n != string::npos) {
641 LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
646 }
else if (keyword ==
"--root") {
647 if (n != string::npos) {
648 RootDir = SGPath::fromLocal8Bit(value.c_str());
653 }
else if (keyword ==
"--aircraft") {
654 if (n != string::npos) {
655 AircraftName = value;
660 }
else if (keyword ==
"--script") {
661 if (n != string::npos) {
662 ScriptName = SGPath::fromLocal8Bit(value.c_str());
667 }
else if (keyword ==
"--initfile") {
668 if (n != string::npos) {
669 ResetName = SGPath::fromLocal8Bit(value.c_str());
675 }
else if (keyword ==
"--property") {
676 if (n != string::npos) {
677 string propName = value.substr(0,value.find(
"="));
678 string propValueString = value.substr(value.find(
"=")+1);
679 double propValue = atof(propValueString.c_str());
680 CommandLineProperties.push_back(propName);
681 CommandLinePropertyValues.push_back(propValue);
687 }
else if (keyword.substr(0,5) ==
"--end") {
688 if (n != string::npos) {
690 end_time = atof( value.c_str() );
692 cerr << endl <<
" Invalid end time given!" << endl << endl;
700 }
else if (keyword ==
"--simulation-rate") {
701 if (n != string::npos) {
703 simulation_rate = atof( value.c_str() );
704 override_sim_rate =
true;
706 cerr << endl <<
" Invalid simulation rate given!" << endl << endl;
714 }
else if (keyword ==
"--catalog") {
716 if (value.size() > 0) AircraftName=value;
717 }
else if (keyword.substr(0,2) !=
"--" && value.empty() ) {
721 SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
723 if (xmlFile.IsScriptFile(path)) ScriptName = path;
724 else if (xmlFile.IsLogDirectiveFile(path)) LogDirectiveName.push_back(path);
725 else if (xmlFile.IsAircraftFile(SGPath(
"aircraft")/keyword/keyword)) AircraftName = keyword;
726 else if (xmlFile.IsInitFile(path)) ResetName = path;
727 else if (xmlFile.IsInitFile(SGPath(
"aircraft")/AircraftName/keyword)) ResetName = SGPath(
"aircraft")/AircraftName/keyword;
729 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
737 cerr <<
"The argument \"" << keyword <<
"\" cannot be interpreted as a file name or option." << endl;
745 if (catalog && !ScriptName.isNull()) {
746 cerr <<
"Cannot specify catalog with script option" << endl << endl;
749 if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
750 cerr <<
"You must specify an initialization file with the aircraft name." << endl << endl;
753 if (!ScriptName.isNull() && !AircraftName.empty()) {
754 cerr <<
"You cannot specify an aircraft file with a script." << endl;
766 cout << endl <<
" JSBSim version " << FDMExec->
GetVersion() << endl << endl;
767 cout <<
" Usage: jsbsim [script file name] [output file names] <options>" << endl << endl;
768 cout <<
" options:" << endl;
769 cout <<
" --help returns this message" << endl;
770 cout <<
" --version returns the version number" << endl;
771 cout <<
" --outputlogfile=<filename> sets (overrides) the name of a data output file" << endl;
772 cout <<
" --logdirectivefile=<filename> specifies the name of a data logging directives file" << endl;
773 cout <<
" (can appear multiple times)" << endl;
774 cout <<
" --root=<path> specifies the JSBSim root directory (where aircraft/, engine/, etc. reside)" << endl;
775 cout <<
" --aircraft=<filename> specifies the name of the aircraft to be modeled" << endl;
776 cout <<
" --script=<filename> specifies a script to run" << endl;
777 cout <<
" --realtime specifies to run in actual real world time" << endl;
778 cout <<
" --nice specifies to run at lower CPU usage" << endl;
779 cout <<
" --nohighlight specifies that console output should be pure text only (no color)" << endl;
780 cout <<
" --suspend specifies to suspend the simulation after initialization" << endl;
781 cout <<
" --initfile=<filename> specifies an initilization file" << endl;
782 cout <<
" --catalog specifies that all properties for this aircraft model should be printed" << endl;
783 cout <<
" (catalog=aircraftname is an optional format)" << endl;
784 cout <<
" --property=<name=value> e.g. --property=simulation/integrator/rate/rotational=1" << endl;
785 cout <<
" --simulation-rate=<rate (double)> specifies the sim dT time or frequency" << endl;
786 cout <<
" If rate specified is less than 1, it is interpreted as" << endl;
787 cout <<
" a time step size, otherwise it is assumed to be a rate in Hertz." << endl;
788 cout <<
" --end=<time (double)> specifies the sim end time" << endl << endl;
790 cout <<
" NOTE: There can be no spaces around the = sign when" << endl;
791 cout <<
" an option is followed by a filename" << endl << endl;