JSBSim Flight Dynamics Model 1.3.3 (16 Oct 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
JSBSim.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: JSBSim.cpp
4 Author: Jon S. Berndt
5 Date started: 08/17/99
6 Purpose: Standalone version of JSBSim.
7 Called by: The USER.
8
9 ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
10
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU Lesser General Public License as published by the Free
13 Software Foundation; either version 2 of the License, or (at your option) any
14 later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19 details.
20
21 You should have received a copy of the GNU Lesser General Public License along
22 with this program; if not, write to the Free Software Foundation, Inc., 59
23 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 Further information about the GNU Lesser General Public License can also be
26 found on the world wide web at http://www.gnu.org.
27
28FUNCTIONAL DESCRIPTION
29--------------------------------------------------------------------------------
30
31This class implements the JSBSim standalone application. It is set up for
32compilation under gnu C++, MSVC++, or other compiler.
33
34HISTORY
35--------------------------------------------------------------------------------
3608/17/99 JSB Created
37
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39INCLUDES
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41
42#include "initialization/FGTrim.h"
43#include "initialization/FGInitialCondition.h"
44#include "FGFDMExec.h"
45#include "input_output/FGXMLFileRead.h"
46#include "input_output/string_utilities.h"
47
48#if !defined(__GNUC__) && !defined(sgi) && !defined(_MSC_VER)
49# include <time>
50#else
51# include <time.h>
52#endif
53
54#if defined(_MSC_VER)
55# include <float.h>
56#elif defined(__GNUC__) && !defined(sgi)
57# define __GNU_VISIBLE 1
58# include <fenv.h>
59#endif
60
61#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
62# define WIN32_LEAN_AND_MEAN
63# include <windows.h>
64# include <mmsystem.h>
65# include <regstr.h>
66# include <sys/types.h>
67# include <sys/timeb.h>
68#else
69# include <sys/time.h>
70#endif
71
72// The flag ENABLE_VIRTUAL_TERMINAL_PROCESSING is not defined for MinGW < 7.0.0
73#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 7
74#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
75#endif
76
77#include <iostream>
78#include <cstdlib>
79
80using namespace std;
82using JSBSim::Element;
83
84/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85GLOBAL DATA
86%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
87
88SGPath RootDir;
89SGPath OutputPath;
90SGPath ScriptName;
91string AircraftName;
92SGPath ResetName;
93SGPath PlanetName;
94vector <string> LogOutputName;
95vector <SGPath> LogDirectiveName;
96vector <string> CommandLineProperties;
97vector <double> CommandLinePropertyValues;
98JSBSim::FGFDMExec* FDMExec;
99JSBSim::FGTrim* trimmer;
100
101bool realtime;
102bool play_nice;
103bool suspend;
104bool catalog;
105bool nohighlight;
106
107double end_time = 1e99;
108double simulation_rate = 1./120.;
109bool override_sim_rate = false;
110double sleep_period=0.01;
111
112/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113FORWARD DECLARATIONS
114%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
115
116bool options(int, char**);
117int real_main(int argc, char* argv[]);
118void PrintHelp(void);
119
120#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
121 double getcurrentseconds(void)
122 {
123 struct timeb tm_ptr;
124 ftime(&tm_ptr);
125 return tm_ptr.time + tm_ptr.millitm*0.001;
126 }
127#else
128 double getcurrentseconds(void)
129 {
130 struct timeval tval;
131 struct timezone tz;
132
133 gettimeofday(&tval, &tz);
134 return (tval.tv_sec + tval.tv_usec*1e-6);
135 }
136#endif
137
138#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
139 void sim_nsleep(long nanosec)
140 {
141 Sleep((DWORD)(nanosec*1e-6)); // convert nanoseconds (passed in) to milliseconds for Win32.
142 }
143#else
144 void sim_nsleep(long nanosec)
145 {
146 struct timespec ts, ts1;
147
148 ts.tv_sec = 0;
149 ts.tv_nsec = nanosec;
150 nanosleep(&ts, &ts1);
151 }
152#endif
153
156class XMLFile : public FGXMLFileRead {
157public:
158 bool IsScriptFile(const SGPath& filename) {
159 bool result=false;
160 Element *document = LoadXMLDocument(filename, false);
161 if (document && document->GetName() == "runscript") result = true;
162 ResetParser();
163 return result;
164 }
165 bool IsLogDirectiveFile(const SGPath& filename) {
166 bool result=false;
167 Element *document = LoadXMLDocument(filename, false);
168 if (document && document->GetName() == "output") result = true;
169 ResetParser();
170 return result;
171 }
172 bool IsAircraftFile(const SGPath& filename) {
173 bool result=false;
174 Element* document = LoadXMLDocument(filename, false);
175 if (document && document->GetName() == "fdm_config") result = true;
176 ResetParser();
177 return result;
178 }
179 bool IsInitFile(const SGPath& filename) {
180 bool result=false;
181 Element *document = LoadXMLDocument(filename, false);
182 if (document && document->GetName() == "initialize") result = true;
183 ResetParser();
184 return result;
185 }
186};
187
192public:
193 Timer() : SGPropertyChangeListener(), isPaused(false) { start(); }
194 void start(void) { initial_seconds = getcurrentseconds(); }
195
197 void valueChanged(SGPropertyNode* prop) override {
198 start();
199 if (isPaused) pause_start_seconds = initial_seconds;
200 }
202 double getElapsedTime(void) { return getcurrentseconds() - initial_seconds; }
203
206 void pause(bool paused) {
207 if (paused) {
208 if (!isPaused) {
209 isPaused = true;
210 pause_start_seconds = getcurrentseconds();
211 }
212 } else {
213 if (isPaused) {
214 isPaused = false;
215 double pause_duration = getcurrentseconds() - pause_start_seconds;
216 initial_seconds += pause_duration; // Shift the initial time to account for the pause duration.
217 }
218 }
219 }
220private:
221 double initial_seconds = 0.0;
222 bool isPaused = false;
223 double pause_start_seconds = 0.0;
224};
225
226/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227CLASS DOCUMENTATION
228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
229
324/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325IMPLEMENTATION
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
327
328int main(int argc, char* argv[])
329{
330#if defined(_MSC_VER) || defined(__MINGW32__)
331 _clearfp();
332 _controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW),
333 _MCW_EM);
334#elif defined(__GNUC__) && !defined(sgi) && !defined(__APPLE__)
335 feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
336#endif
337
338 try {
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;
343 return 1;
344 } catch (const char* msg) {
345 std::cerr << "FATAL ERROR: JSBSim terminated with an exception."
346 << std::endl << "The message was: " << msg << std::endl;
347 return 1;
348 } catch (const JSBSim::BaseException& e) {
349 std::cerr << "FATAL ERROR: JSBSim terminated with an exception."
350 << std::endl << "The message was: " << e.what() << std::endl;
351 return 1;
352 } catch (...) {
353 std::cerr << "FATAL ERROR: JSBSim terminated with an unknown exception."
354 << std::endl;
355 return 1;
356 }
357 return 0;
358}
359
360int real_main(int argc, char* argv[])
361{
362 // *** INITIALIZATIONS *** //
363
364 ScriptName = "";
365 AircraftName = "";
366 ResetName = "";
367 PlanetName = "";
368 OutputPath = SGPath(".");
369 LogOutputName.clear();
370 LogDirectiveName.clear();
371 bool result = false, success;
372 double frame_duration;
373
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;
379
380 realtime = false;
381 play_nice = false;
382 suspend = false;
383 catalog = false;
384 nohighlight = false;
385
386 // *** PARSE OPTIONS PASSED INTO THIS SPECIFIC APPLICATION: JSBSim *** //
387 success = options(argc, argv);
388 if (!success) {
389 PrintHelp();
390 exit(-1);
391 }
392
393 // *** SET UP JSBSIM *** //
394 FDMExec = new JSBSim::FGFDMExec();
395 FDMExec->SetRootDir(RootDir);
396 FDMExec->SetAircraftPath(SGPath("aircraft"));
397 FDMExec->SetEnginePath(SGPath("engine"));
398 FDMExec->SetSystemsPath(SGPath("systems"));
399 FDMExec->SetOutputPath(OutputPath);
400 FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time);
401 FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration);
402
403 Timer timer;
404 SGPropertyNode_ptr reset_node = FDMExec->GetPropertyManager()->GetNode("simulation/reset");
405 reset_node->addChangeListener(&timer);
406
407 // Check whether to disable console highlighting output on Windows.
408 // Support was added to Windows for Virtual Terminal codes by a particular
409 // Windows 10 release.
410#ifdef _WIN32
411 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
412 DWORD dwMode = 0;
413 GetConsoleMode(hStdOut, &dwMode);
414 if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0)
415 nohighlight = true;
416#endif
417
418 if (nohighlight) {
419 auto logger = dynamic_cast<JSBSim::FGLogConsole*>(JSBSim::GetLogger().get());
420 if (logger) logger->DisableHighLighting();
421 }
422
423 if (simulation_rate < 1.0 )
424 FDMExec->Setdt(simulation_rate);
425 else
426 FDMExec->Setdt(1.0/simulation_rate);
427
428 if (override_sim_rate) override_sim_rate_value = FDMExec->GetDeltaT();
429
430 // SET PROPERTY VALUES THAT ARE GIVEN ON THE COMMAND LINE and which are for the simulation only.
431
432 for (unsigned int i=0; i<CommandLineProperties.size(); i++) {
433
434 if (CommandLineProperties[i].find("simulation") != std::string::npos) {
435 if (FDMExec->GetPropertyManager()->GetNode(CommandLineProperties[i])) {
436 FDMExec->SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
437 }
438 }
439 }
440
441 if (!PlanetName.isNull()) {
442 result = FDMExec->LoadPlanet(PlanetName, false);
443
444 if (!result) {
445 cerr << "Planet file " << PlanetName << " was not successfully loaded" << endl;
446 delete FDMExec;
447 exit(-1);
448 }
449 }
450
451 // *** OPTION A: LOAD A SCRIPT, WHICH LOADS EVERYTHING ELSE *** //
452 if (!ScriptName.isNull()) {
453
454 result = FDMExec->LoadScript(ScriptName, override_sim_rate_value, ResetName);
455
456 if (!result) {
457 cerr << "Script file " << ScriptName << " was not successfully loaded" << endl;
458 delete FDMExec;
459 exit(-1);
460 }
461
462 // *** OPTION B: LOAD AN AIRCRAFT AND A SET OF INITIAL CONDITIONS *** //
463 } else if (!AircraftName.empty() || !ResetName.isNull()) {
464
465 if (catalog) FDMExec->SetDebugLevel(0);
466
467 if ( ! FDMExec->LoadModel(SGPath("aircraft"),
468 SGPath("engine"),
469 SGPath("systems"),
470 AircraftName)) {
471 cerr << " JSBSim could not be started" << endl << endl;
472 delete FDMExec;
473 exit(-1);
474 }
475
476 if (catalog) {
477 FDMExec->PrintPropertyCatalog();
478 delete FDMExec;
479 return 0;
480 }
481
482 auto IC = FDMExec->GetIC();
483 if ( ! IC->Load(ResetName)) {
484 delete FDMExec;
485 cerr << "Initialization unsuccessful" << endl;
486 exit(-1);
487 }
488
489 } else {
490 cout << " No Aircraft, Script, or Reset information given" << endl << endl;
491 delete FDMExec;
492 exit(-1);
493 }
494
495 // Load output directives file[s], if given
496 for (unsigned int i=0; i<LogDirectiveName.size(); i++) {
497 if (!LogDirectiveName[i].isNull()) {
498 if (!FDMExec->SetOutputDirectives(LogDirectiveName[i])) {
499 cout << "Output directives not properly set in file " << LogDirectiveName[i] << endl;
500 delete FDMExec;
501 exit(-1);
502 }
503 }
504 }
505
506 // OVERRIDE OUTPUT FILE NAME. THIS IS USEFUL FOR CASES WHERE MULTIPLE
507 // RUNS ARE BEING MADE (SUCH AS IN A MONTE CARLO STUDY) AND THE OUTPUT FILE
508 // NAME MUST BE SET EACH TIME TO AVOID THE PREVIOUS RUN DATA FROM BEING OVER-
509 // WRITTEN.
510 for (unsigned int i=0; i<LogOutputName.size(); i++) {
511 string old_filename = FDMExec->GetOutputFileName(i);
512 if (!FDMExec->SetOutputFileName(i, LogOutputName[i])) {
513 cout << "Output filename could not be set" << endl;
514 } else {
515 cout << "Output filename change from " << old_filename << " from aircraft"
516 " configuration file to " << LogOutputName[i] << " specified on"
517 " command line" << endl;
518 }
519 }
520
521 // SET PROPERTY VALUES THAT ARE GIVEN ON THE COMMAND LINE
522
523 for (unsigned int i=0; i<CommandLineProperties.size(); i++) {
524
525 if (!FDMExec->GetPropertyManager()->GetNode(CommandLineProperties[i])) {
526 cerr << endl << " No property by the name " << CommandLineProperties[i] << endl;
527 delete FDMExec;
528 exit(-1);
529 } else {
530 FDMExec->SetPropertyValue(CommandLineProperties[i], CommandLinePropertyValues[i]);
531 }
532 }
533
534 FDMExec->RunIC();
535
536 // PRINT SIMULATION CONFIGURATION
537 FDMExec->PrintSimulationConfiguration();
538
539 // Dump the simulation state (position, orientation, etc.)
540 FDMExec->GetPropagate()->DumpState();
541
542 // Perform trim if requested via the initialization file
543 JSBSim::TrimMode icTrimRequested = (JSBSim::TrimMode)FDMExec->GetIC()->TrimRequested();
544 if (icTrimRequested != JSBSim::TrimMode::tNone) {
545 trimmer = new JSBSim::FGTrim( FDMExec, icTrimRequested );
546 try {
547 trimmer->DoTrim();
548
549 if (FDMExec->GetDebugLevel() > 0)
550 trimmer->Report();
551
552 delete trimmer;
553 } catch (string& msg) {
554 cerr << endl << msg << endl << endl;
555 exit(1);
556 }
557 }
558
559 {
560 // Using FGLogging class so that the parameter --nohighlight can disable the formatting
561 JSBSim::FGLogging out(JSBSim::LogLevel::STDOUT);
562 out << endl << JSBSim::LogFormat::GREEN << JSBSim::LogFormat::BOLD
563 << "---- JSBSim Execution beginning ... --------------------------------------------"
564 << JSBSim::LogFormat::RESET << endl << endl;
565 }
566
567 result = FDMExec->Run(); // MAKE AN INITIAL RUN
568
569 if (suspend) FDMExec->Hold();
570
571 // Print actual time at start
572 char s[100];
573 time_t tod;
574 time(&tod);
575 struct tm local;
576#if defined(_MSC_VER) || defined(__MINGW32__)
577 localtime_s(&local, &tod);
578#else
579 localtime_r(&tod, &local);
580#endif
581 strftime(s, 99, "%A %B %d %Y %X", &local);
582 cout << "Start: " << s << " (HH:MM:SS)" << endl;
583
584 frame_duration = FDMExec->GetDeltaT();
585 if (realtime) sleep_nseconds = (long)(frame_duration*1e9);
586 else sleep_nseconds = (sleep_period )*1e9; // 0.01 seconds
587
588 tzset();
589 timer.start();
590
591 // *** CYCLIC EXECUTION LOOP, AND MESSAGE READING *** //
592 while (result && FDMExec->GetSimTime() <= end_time) {
593 // Check if increment then hold is on and take appropriate actions if it is
594 // Iterate is not supported in realtime - only in batch and playnice modes
595 FDMExec->CheckIncrementalHold();
596
597 // if running realtime, throttle the execution, else just run flat-out fast
598 // unless "playing nice", in which case sleep for a while (0.01 seconds) each frame.
599 // If suspended, then don't increment cumulative realtime "stopwatch".
600
601 if ( ! FDMExec->Holding()) {
602 if ( ! realtime ) { // ------------ RUNNING IN BATCH MODE
603
604 result = FDMExec->Run();
605
606 if (play_nice) sim_nsleep(sleep_nseconds);
607
608 } else { // ------------ RUNNING IN REALTIME MODE
609 timer.pause(false);
610 actual_elapsed_time = timer.getElapsedTime();
611
612 double sim_lag_time = actual_elapsed_time - FDMExec->GetSimTime(); // How far behind sim-time is from actual elapsed time.
613 double cycle_start = getcurrentseconds();
614
615 for (int i=0; i<(int)(sim_lag_time/frame_duration); i++) { // catch up sim time to actual elapsed time.
616 result = FDMExec->Run();
617 cycle_duration = getcurrentseconds() - cycle_start; // Calculate cycle duration
618 cycle_start = getcurrentseconds(); // Get new current_seconds
619 if (FDMExec->Holding()) break;
620 }
621
622 if (play_nice) sim_nsleep(sleep_nseconds);
623
624 if (FDMExec->GetSimTime() >= new_five_second_value) { // Print out elapsed time every five seconds.
625 cout << "Simulation elapsed time: " << FDMExec->GetSimTime() << endl;
626 new_five_second_value += 5.0;
627 }
628 }
629 } else { // Suspended
630 timer.pause(true);
631 sim_nsleep(sleep_nseconds);
632 result = FDMExec->Run();
633 }
634
635 }
636
637 // PRINT ENDING CLOCK TIME
638 time(&tod);
639#if defined(_MSC_VER) || defined(__MINGW32__)
640 localtime_s(&local, &tod);
641#else
642 localtime_r(&tod, &local);
643#endif
644 strftime(s, 99, "%A %B %d %Y %X", &local);
645 cout << "End: " << s << " (HH:MM:SS)" << endl;
646
647 // CLEAN UP
648 delete FDMExec;
649
650 return 0;
651}
652
653//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654
655#define gripe cerr << "Option '" << keyword \
656 << "' requires a value, as in '" \
657 << keyword << "=something'" << endl << endl;
658
659bool options(int count, char **arg)
660{
661 int i;
662 bool result = true;
663
664 if (count == 1) {
665 PrintHelp();
666 exit(0);
667 }
668
669 cout.setf(ios_base::fixed);
670
671 for (i=1; i<count; i++) {
672 string argument = string(arg[i]);
673 string keyword(argument);
674 string value("");
675 string::size_type n=argument.find("=");
676
677 if (n != string::npos && n > 0) {
678 keyword = argument.substr(0, n);
679 value = argument.substr(n+1);
680 }
681
682 if (keyword == "--help") {
683 PrintHelp();
684 exit(0);
685 } else if (keyword == "--version") {
686 cout << endl << " JSBSim Version: " << FDMExec->GetVersion() << endl << endl;
687 exit (0);
688 } else if (keyword == "--realtime") {
689 realtime = true;
690 } else if (keyword == "--nice") {
691 play_nice = true;
692 if (n != string::npos) {
693 try {
694 sleep_period = JSBSim::atof_locale_c( value.c_str() );
695 } catch (...) {
696 cerr << endl << " Invalid sleep period given!" << endl << endl;
697 result = false;
698 }
699 } else {
700 sleep_period = 0.01;
701 }
702 } else if (keyword == "--suspend") {
703 suspend = true;
704 } else if (keyword == "--nohighlight") {
705 nohighlight = true;
706 } else if (keyword == "--outputlogfile") {
707 if (n != string::npos) {
708 LogOutputName.push_back(value);
709 }
710 } else if (keyword == "--logdirectivefile") {
711 if (n != string::npos) {
712 LogDirectiveName.push_back(SGPath::fromLocal8Bit(value.c_str()));
713 } else {
714 gripe;
715 exit(1);
716 }
717 } else if (keyword == "--root") {
718 if (n != string::npos) {
719 RootDir = SGPath::fromLocal8Bit(value.c_str());
720 } else {
721 gripe;
722 exit(1);
723 }
724 } else if (keyword == "--outputpath") {
725 if (n != string::npos) {
726 OutputPath = SGPath::fromLocal8Bit(value.c_str());
727 } else {
728 gripe;
729 exit(1);
730 }
731 } else if (keyword == "--aircraft") {
732 if (n != string::npos) {
733 AircraftName = value;
734 } else {
735 gripe;
736 exit(1);
737 }
738 } else if (keyword == "--script") {
739 if (n != string::npos) {
740 ScriptName = SGPath::fromLocal8Bit(value.c_str());
741 } else {
742 gripe;
743 exit(1);
744 }
745 } else if (keyword == "--initfile") {
746 if (n != string::npos) {
747 ResetName = SGPath::fromLocal8Bit(value.c_str());
748 } else {
749 gripe;
750 exit(1);
751 }
752 } else if (keyword == "--planet") {
753 if (n != string::npos) {
754 PlanetName = SGPath::fromLocal8Bit(value.c_str());
755 } else {
756 gripe;
757 exit(1);
758 }
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);
763 double propValue;
764 try {
765 propValue = JSBSim::atof_locale_c(propValueString.c_str());
766 } catch (JSBSim::InvalidNumber&) {
767 gripe;
768 exit(1);
769 }
770 CommandLineProperties.push_back(propName);
771 CommandLinePropertyValues.push_back(propValue);
772 } else {
773 gripe;
774 exit(1);
775 }
776
777 } else if (keyword.substr(0,5) == "--end") {
778 if (n != string::npos) {
779 try {
780 end_time = JSBSim::atof_locale_c( value.c_str() );
781 } catch (...) {
782 cerr << endl << " Invalid end time given!" << endl << endl;
783 result = false;
784 }
785 } else {
786 gripe;
787 exit(1);
788 }
789
790 } else if (keyword == "--simulation-rate") {
791 if (n != string::npos) {
792 try {
793 simulation_rate = JSBSim::atof_locale_c( value.c_str() );
794 override_sim_rate = true;
795 } catch (...) {
796 cerr << endl << " Invalid simulation rate given!" << endl << endl;
797 result = false;
798 }
799 } else {
800 gripe;
801 exit(1);
802 }
803
804 } else if (keyword == "--catalog") {
805 catalog = true;
806 if (!value.empty()) AircraftName=value;
807 } else if (keyword.substr(0,2) != "--" && value.empty() ) {
808 // See what kind of files we are specifying on the command line
809
810 XMLFile xmlFile;
811 SGPath path = SGPath::fromLocal8Bit(keyword.c_str());
812
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;
818 else {
819 cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
820 exit(1);
821 }
822
823 }
824 else //Unknown keyword so print the help file, the bad keyword and abort
825 {
826 PrintHelp();
827 cerr << "The argument \"" << keyword << "\" cannot be interpreted as a file name or option." << endl;
828 exit(1);
829 }
830
831 }
832
833 // Post-processing for script options. check for incompatible options.
834
835 if (catalog && !ScriptName.isNull()) {
836 cerr << "Cannot specify catalog with script option" << endl << endl;
837 result = false;
838 }
839 if (!AircraftName.empty() && ResetName.isNull() && !catalog) {
840 cerr << "You must specify an initialization file with the aircraft name." << endl << endl;
841 result = false;
842 }
843 if (!ScriptName.isNull() && !AircraftName.empty()) {
844 cerr << "You cannot specify an aircraft file with a script." << endl;
845 result = false;
846 }
847
848 return result;
849
850}
851
852//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853
854void PrintHelp(void)
855{
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;
881
882 cout << " NOTE: There can be no spaces around the = sign when" << endl;
883 cout << " an option is followed by a filename" << endl << endl;
884}
const std::string & GetName(void) const
Retrieves the element name.
Encapsulates the JSBSim simulation executive.
Definition FGFDMExec.h:185
void SetPropertyValue(const std::string &property, double value)
Sets a property value.
Definition FGFDMExec.h:415
std::shared_ptr< FGInitialCondition > GetIC(void) const
Returns a pointer to the FGInitialCondition object.
Definition FGFDMExec.h:390
bool SetSystemsPath(const SGPath &path)
Set the path to the systems config file directories.
Definition FGFDMExec.h:337
bool SetOutputFileName(const int n, const std::string &fname)
Sets (or overrides) the output filename.
Definition FGFDMExec.h:460
void SetDebugLevel(int level)
Sets the debug level.
Definition FGFDMExec.h:514
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.
Definition FGFDMExec.h:314
int GetDebugLevel(void) const
Retrieves the current debug level setting.
Definition FGFDMExec.h:606
bool SetOutputPath(const SGPath &path)
Set the directory where the output files will be written.
Definition FGFDMExec.h:348
void SetRootDir(const SGPath &rootDir)
Set the root directory that is used to obtain absolute paths from relative paths.
Definition FGFDMExec.h:590
std::string GetOutputFileName(int n) const
Retrieves the current output filename.
Definition FGFDMExec.h:466
double GetDeltaT(void) const
Returns the simulation delta T.
Definition FGFDMExec.h:557
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.
Definition FGFDMExec.h:447
double GetSimTime(void) const
Returns the cumulative simulation time in seconds.
Definition FGFDMExec.h:554
void Setdt(double delta_t)
Sets the integration time step for the simulation executive.
Definition FGFDMExec.h:576
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Definition FGFDMExec.h:422
void Hold(void)
Pauses execution by preventing time from incrementing.
Definition FGFDMExec.h:493
bool SetAircraftPath(const SGPath &path)
Set the path to the aircraft config file directories.
Definition FGFDMExec.h:326
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).
Definition FGFDMExec.h:501
static const std::string & GetVersion(void)
Returns the version number of JSBSim.
Definition FGJSBBase.h:148
The trimming routine for JSBSim.
Definition FGTrim.h:126
void Report(void)
Print the results of the trim.
Definition FGTrim.cpp:121
bool DoTrim(void)
Execute the trim.
Definition FGTrim.cpp:195
The property change listener interface.
Definition props.hxx:720
A node in a property tree.
Definition props.hxx:747
The Timer class measures the elapsed real time and can be paused and resumed.
Definition JSBSim.cpp:191
void pause(bool paused)
Pause the timer if the paused parameter is true and resume it if the paused parameter is false.
Definition JSBSim.cpp:206
void valueChanged(SGPropertyNode *prop) override
Restart the timer when the listened property is modified.
Definition JSBSim.cpp:197
double getElapsedTime(void)
Get the elapsed real time in seconds since the timer was started.
Definition JSBSim.cpp:202
This class is solely for the purpose of determining what type of file is given on the command line.
Definition JSBSim.cpp:156
FGLogger_ptr GetLogger(void)
Returns the active logger for the current thread.
Definition FGLog.cpp:52