diff --git a/.github/workflows/cpp-python-build.yml b/.github/workflows/cpp-python-build.yml index 4e60bb9d77..792f1c8e62 100644 --- a/.github/workflows/cpp-python-build.yml +++ b/.github/workflows/cpp-python-build.yml @@ -509,6 +509,17 @@ jobs: rm -f _jsbsim.cxx # Make sure that jsbsim.cxx is not stored in the source distribution python -m build --sdist echo "::endgroup::" + - name: Check reset for real time execution + if: matrix.os == 'macos-14' + run: | + start_time=$(date +%s) + ./build/src/JSBSim scripts/c172_cruise_8K.xml --realtime --nice + end_time=$(date +%s) + elapsed_time=$((end_time - start_time)) + if [ $elapsed_time -lt 90 ]; then + echo "Failed - Program finished in less than 90 seconds" + exit 1 + fi # On failure, upload logs - name: On failure - Upload logs diff --git a/scripts/c172_cruise_8K.xml b/scripts/c172_cruise_8K.xml index ef4161e561..61a0443290 100644 --- a/scripts/c172_cruise_8K.xml +++ b/scripts/c172_cruise_8K.xml @@ -6,8 +6,8 @@ This run is for testing the C172 altitude hold autopilot and cruise performance - - + + simulation/run_id @@ -26,17 +26,17 @@ - + simulation/sim-time-sec ge 0.01 - + - + @@ -102,8 +102,8 @@ - simulation/sim-time-sec >= 30.0 - simulation/terminate != 1 + simulation/sim-time-sec >= 25.0 + simulation/run_id lt 2 @@ -115,16 +115,5 @@ simulation/run_id - - - - simulation/run_id ge 3 - - - - simulation/terminate - - - diff --git a/src/JSBSim.cpp b/src/JSBSim.cpp index 1eb665ea85..156e491317 100644 --- a/src/JSBSim.cpp +++ b/src/JSBSim.cpp @@ -183,6 +183,44 @@ class XMLFile : public FGXMLFileRead { } }; +/** The Timer class measures the elapsed real time and can be paused and resumed. + It inherits from SGPropertyChangeListener to restart the timer whenever a + property change is detected. */ +class Timer : public SGPropertyChangeListener { +public: + Timer() : SGPropertyChangeListener(), isPaused(false) { start(); } + void start(void) { initial_seconds = getcurrentseconds(); } + + /// Restart the timer when the listened property is modified. + void valueChanged(SGPropertyNode* prop) override { + start(); + if (isPaused) pause_start_seconds = initial_seconds; + } + /// Get the elapsed real time in seconds since the timer was started. + double getElapsedTime(void) { return getcurrentseconds() - initial_seconds; } + + /** Pause the timer if the `paused` parameter is true and resume it if the + `paused` parameter is false. */ + void pause(bool paused) { + if (paused) { + if (!isPaused) { + isPaused = true; + pause_start_seconds = getcurrentseconds(); + } + } else { + if (isPaused) { + isPaused = false; + double pause_duration = getcurrentseconds() - pause_start_seconds; + initial_seconds += pause_duration; // Shift the initial time to account for the pause duration. + } + } + } +private: + double initial_seconds = 0.0; + bool isPaused = false; + double pause_start_seconds = 0.0; +}; + /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% CLASS DOCUMENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ @@ -328,16 +366,10 @@ int real_main(int argc, char* argv[]) LogOutputName.clear(); LogDirectiveName.clear(); bool result = false, success; - bool was_paused = false; - double frame_duration; double new_five_second_value = 0.0; double actual_elapsed_time = 0; - double initial_seconds = 0; - double current_seconds = 0.0; - double paused_seconds = 0.0; - double sim_lag_time = 0; double cycle_duration = 0.0; double override_sim_rate_value = 0.0; long sleep_nseconds = 0; @@ -365,6 +397,10 @@ int real_main(int argc, char* argv[]) FDMExec->GetPropertyManager()->Tie("simulation/frame_start_time", &actual_elapsed_time); FDMExec->GetPropertyManager()->Tie("simulation/cycle_duration", &cycle_duration); + Timer timer; + SGPropertyNode_ptr reset_node = FDMExec->GetPropertyManager()->GetNode("simulation/reset"); + reset_node->addChangeListener(&timer); + // Check whether to disable console highlighting output on Windows. // Support was added to Windows for Virtual Terminal codes by a particular // Windows 10 release. @@ -540,7 +576,7 @@ int real_main(int argc, char* argv[]) else sleep_nseconds = (sleep_period )*1e9; // 0.01 seconds tzset(); - current_seconds = initial_seconds = getcurrentseconds(); + timer.start(); // *** CYCLIC EXECUTION LOOP, AND MESSAGE READING *** // while (result && FDMExec->GetSimTime() <= end_time) { @@ -560,20 +596,16 @@ int real_main(int argc, char* argv[]) if (play_nice) sim_nsleep(sleep_nseconds); } else { // ------------ RUNNING IN REALTIME MODE + timer.pause(false); + actual_elapsed_time = timer.getElapsedTime(); + + double sim_lag_time = actual_elapsed_time - FDMExec->GetSimTime(); // How far behind sim-time is from actual elapsed time. + double cycle_start = getcurrentseconds(); - // "was_paused" will be true if entering this "run" loop from a paused state. - if (was_paused) { - initial_seconds += paused_seconds; - was_paused = false; - } - current_seconds = getcurrentseconds(); // Seconds since 1 Jan 1970 - actual_elapsed_time = current_seconds - initial_seconds; // Real world elapsed seconds since start - sim_lag_time = actual_elapsed_time - FDMExec->GetSimTime(); // How far behind sim-time is from actual - // elapsed time. for (int i=0; i<(int)(sim_lag_time/frame_duration); i++) { // catch up sim time to actual elapsed time. result = FDMExec->Run(); - cycle_duration = getcurrentseconds() - current_seconds; // Calculate cycle duration - current_seconds = getcurrentseconds(); // Get new current_seconds + cycle_duration = getcurrentseconds() - cycle_start; // Calculate cycle duration + cycle_start = getcurrentseconds(); // Get new current_seconds if (FDMExec->Holding()) break; } @@ -585,8 +617,7 @@ int real_main(int argc, char* argv[]) } } } else { // Suspended - was_paused = true; - paused_seconds = getcurrentseconds() - current_seconds; + timer.pause(true); sim_nsleep(sleep_nseconds); result = FDMExec->Run(); } diff --git a/src/simgear/props/props.hxx b/src/simgear/props/props.hxx index b06aee9bdc..89af5e5590 100644 --- a/src/simgear/props/props.hxx +++ b/src/simgear/props/props.hxx @@ -228,7 +228,7 @@ public: */ virtual simgear::props::Type getType() const = 0; virtual ~SGRaw() {} - + /** * Create a new deep copy of this raw value. * @@ -244,7 +244,7 @@ public: class SGRawExtended : public SGRaw { public: - /** + /** * Make an SGRawValueContainer from the SGRawValue. * * This is a virtual function of SGRawExtended so that @@ -723,7 +723,7 @@ typedef std::vector PropertyList; *

Any class that needs to listen for property changes must implement * this interface.

*/ -class SGPropertyChangeListener +class JSBSIM_API SGPropertyChangeListener { public: virtual ~SGPropertyChangeListener (); @@ -1150,7 +1150,7 @@ public: * Set all of the mode attributes for the property node. */ void setAttributes (int attr) { _attr = attr; } - + // // Leaf Value (primitive). @@ -1284,7 +1284,7 @@ public: { return setValue(&val[0]); } - + /** * Set relative node to given value and afterwards make read only. * @@ -1344,7 +1344,7 @@ public: * Print the value of the property to a stream. */ std::ostream& printOn(std::ostream& stream) const; - + // // Data binding. // @@ -2136,4 +2136,4 @@ private: #endif // __PROPS_HXX -// end of props.hxx \ No newline at end of file +// end of props.hxx