From e204929638d0b8ae6a837789760c65427163b7fa Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Wed, 3 Apr 2024 10:47:31 +0200 Subject: [PATCH 1/8] File aux.rs renamed to traits.rs --- src/aux.rs | 96 ------------------------------------------------------ 1 file changed, 96 deletions(-) delete mode 100644 src/aux.rs diff --git a/src/aux.rs b/src/aux.rs deleted file mode 100644 index a1b6b37..0000000 --- a/src/aux.rs +++ /dev/null @@ -1,96 +0,0 @@ -/// Trait that defines the methods that a DEVS event bag set must implement. -/// -/// # Safety -/// -/// This trait must be implemented via macros. Do not implement it manually. -pub unsafe trait Bag { - /// Returns `true` if the ports are empty. - fn is_empty(&self) -> bool; - - /// Clears the ports, removing all values. - fn clear(&mut self); -} - -/// Interface for DEVS components. All DEVS components must implement this trait. -/// -/// # Safety -/// -/// This trait must be implemented via macros. Do not implement it manually. -pub unsafe trait Component { - /// Input event bag of the model. - type Input: Bag; - - /// Output event bag of the model. - type Output: Bag; - - /// Returns the last time the component was updated. - fn get_t_last(&self) -> f64; - - /// Sets the last time the component was updated. - fn set_t_last(&mut self, t_last: f64); - - /// Returns the next time the component will be updated. - fn get_t_next(&self) -> f64; - - /// Sets the next time the component will be updated. - fn set_t_next(&mut self, t_next: f64); - - /// Returns a reference to the model's input event bag. - fn get_input(&self) -> &Self::Input; - - /// Returns a mutable reference to the model's input event bag. - fn get_input_mut(&mut self) -> &mut Self::Input; - - /// Returns a reference to the model's output event bag. - fn get_output(&self) -> &Self::Output; - - /// Returns a mutable reference to the model's output event bag. - fn get_output_mut(&mut self) -> &mut Self::Output; - - /// Clears the input bag, removing all values. - #[inline] - fn clear_input(&mut self) { - self.get_input_mut().clear() - } - - /// Clears the output bag, removing all values. - #[inline] - fn clear_output(&mut self) { - self.get_output_mut().clear() - } -} - -/// Partial interface for DEVS atomic models. -/// It is used as a helper trait to implement the [`crate::Atomic`] trait. -/// -/// # Safety -/// -/// This trait must be implemented via macros. Do not implement it manually. -pub unsafe trait PartialAtomic: Component { - /// The data type used to represent the state of the model. - type State; -} - -/// Interface for simulating DEVS models. All DEVS models must implement this trait. -/// -/// # Safety -/// -/// This trait must be implemented via macros. Do not implement it manually. -pub unsafe trait AbstractSimulator: Component { - /// It starts the simulation, setting the initial time to t_start. - /// It returns the time for the next state transition of the inner DEVS model. - fn start(&mut self, t_start: f64) -> f64; - - /// It stops the simulation, setting the last time to t_stop. - fn stop(&mut self, t_stop: f64); - - /// Executes output functions and propagates messages according to EOCs. - /// Internally, it checks that the model is imminent before executing. - fn lambda(&mut self, t: f64); - - /// Propagates messages according to ICs and EICs and executes model transition functions. - /// It also clears all the input and output ports. - /// Internally, it checks that the model is imminent before executing. - /// Finally, it returns the time for the next state transition of the inner DEVS model. - fn delta(&mut self, t: f64) -> f64; -} From 4879bb098027391961b349224aa4c76c011c37af Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Wed, 3 Apr 2024 10:48:58 +0200 Subject: [PATCH 2/8] Update files --- macros/src/component.rs | 2 +- macros/src/component/atomic.rs | 28 +++++----- macros/src/component/coupled.rs | 28 +++++----- macros/src/component/port.rs | 2 +- src/lib.rs | 4 +- src/port.rs | 2 +- src/simulator.rs | 2 +- src/simulator/std.rs | 2 +- src/traits.rs | 96 +++++++++++++++++++++++++++++++++ 9 files changed, 131 insertions(+), 35 deletions(-) create mode 100644 src/traits.rs diff --git a/macros/src/component.rs b/macros/src/component.rs index ae246cd..89102a9 100644 --- a/macros/src/component.rs +++ b/macros/src/component.rs @@ -181,7 +181,7 @@ impl Component { } } } - unsafe impl xdevs::aux::Component for #ident { + unsafe impl xdevs::traits::Component for #ident { type Input = #input_ident; type Output = #output_ident; #[inline] diff --git a/macros/src/component/atomic.rs b/macros/src/component/atomic.rs index 4b242ab..61d7f57 100644 --- a/macros/src/component/atomic.rs +++ b/macros/src/component/atomic.rs @@ -37,18 +37,18 @@ impl State { }; quote! { - unsafe impl xdevs::aux::PartialAtomic for #atomic_ident { + unsafe impl xdevs::traits::PartialAtomic for #atomic_ident { type State = #state_ty; } - unsafe impl xdevs::aux::AbstractSimulator for #atomic_ident { + unsafe impl xdevs::traits::AbstractSimulator for #atomic_ident { #[inline] fn start(&mut self, t_start: f64) -> f64 { // set t_last to t_start - xdevs::aux::Component::set_t_last(self, t_start); + xdevs::traits::Component::set_t_last(self, t_start); // start state and get t_next from ta ::start(&mut self.state); let t_next = t_start + ::ta(&self.state); - xdevs::aux::Component::set_t_next(self, t_next); + xdevs::traits::Component::set_t_next(self, t_next); t_next } @@ -57,30 +57,30 @@ impl State { // stop state ::stop(&mut self.state); // set t_last to t_stop and t_next to infinity - xdevs::aux::Component::set_t_last(self, t_stop); - xdevs::aux::Component::set_t_next(self, f64::INFINITY); + xdevs::traits::Component::set_t_last(self, t_stop); + xdevs::traits::Component::set_t_next(self, f64::INFINITY); } #[inline] fn lambda(&mut self, t: f64) { - if t >= xdevs::aux::Component::get_t_next(self) { + if t >= xdevs::traits::Component::get_t_next(self) { // execute atomic model's lambda if applies ::lambda(&self.state, &mut self.output); } } #[inline] fn delta(&mut self, t: f64) -> f64 { - let mut t_next = xdevs::aux::Component::get_t_next(self); - if !xdevs::aux::Bag::is_empty(&self.input) { + let mut t_next = xdevs::traits::Component::get_t_next(self); + if !xdevs::traits::Bag::is_empty(&self.input) { if t >= t_next { // confluent transition ::delta_conf(&mut self.state, &self.input); } else { // external transition - let e = t - xdevs::aux::Component::get_t_last(self); + let e = t - xdevs::traits::Component::get_t_last(self); ::delta_ext(&mut self.state, e, &self.input); } // clear input events - xdevs::aux::Component::clear_input(self); + xdevs::traits::Component::clear_input(self); } else if t >= t_next { // internal transition ::delta_int(&mut self.state); @@ -88,11 +88,11 @@ impl State { return t_next; // nothing to do } // clear output events - xdevs::aux::Component::clear_output(self); + xdevs::traits::Component::clear_output(self); // get t_next from ta and set new t_last and t_next t_next = t + ::ta(&self.state); - xdevs::aux::Component::set_t_last(self, t); - xdevs::aux::Component::set_t_next(self, t_next); + xdevs::traits::Component::set_t_last(self, t); + xdevs::traits::Component::set_t_next(self, t_next); t_next } diff --git a/macros/src/component/coupled.rs b/macros/src/component/coupled.rs index b6e88a1..f692cfd 100644 --- a/macros/src/component/coupled.rs +++ b/macros/src/component/coupled.rs @@ -24,16 +24,16 @@ impl Coupled { }; quote! { - unsafe impl xdevs::aux::AbstractSimulator for #coupled_ident { + unsafe impl xdevs::traits::AbstractSimulator for #coupled_ident { #[inline] fn start(&mut self, t_start: f64) -> f64 { // set t_last to t_start - xdevs::aux::Component::set_t_last(self, t_start); + xdevs::traits::Component::set_t_last(self, t_start); // get minimum t_next from all components let mut t_next = f64::INFINITY; - #(t_next = f64::min(t_next, xdevs::aux::AbstractSimulator::start(&mut self.#component, t_start));)* + #(t_next = f64::min(t_next, xdevs::traits::AbstractSimulator::start(&mut self.#component, t_start));)* // set t_next to minimum t_next - xdevs::aux::Component::set_t_next(self, t_next); + xdevs::traits::Component::set_t_next(self, t_next); t_next } @@ -41,17 +41,17 @@ impl Coupled { #[inline] fn stop(&mut self, t_stop: f64) { // stop all components - #(xdevs::aux::AbstractSimulator::stop(&mut self.#component, t_stop);)* + #(xdevs::traits::AbstractSimulator::stop(&mut self.#component, t_stop);)* // set t_last to t_stop and t_next to infinity - xdevs::aux::Component::set_t_last(self, t_stop); - xdevs::aux::Component::set_t_next(self, f64::INFINITY); + xdevs::traits::Component::set_t_last(self, t_stop); + xdevs::traits::Component::set_t_next(self, f64::INFINITY); } #[inline] fn lambda(&mut self, t: f64) { - if t >= xdevs::aux::Component::get_t_next(self) { + if t >= xdevs::traits::Component::get_t_next(self) { // propagate lambda to all components - #(xdevs::aux::AbstractSimulator::lambda(&mut self.#component, t);)* + #(xdevs::traits::AbstractSimulator::lambda(&mut self.#component, t);)* // propagate EOCs #(#eoc);* } @@ -63,13 +63,13 @@ impl Coupled { #(#xic);* // get minimum t_next from all components after executing their delta let mut t_next = f64::INFINITY; - #(t_next = f64::min(t_next, xdevs::aux::AbstractSimulator::delta(&mut self.#component, t));)* + #(t_next = f64::min(t_next, xdevs::traits::AbstractSimulator::delta(&mut self.#component, t));)* // clear input and output events - xdevs::aux::Component::clear_output(self); - xdevs::aux::Component::clear_input(self); + xdevs::traits::Component::clear_output(self); + xdevs::traits::Component::clear_input(self); // set t_last to t and t_next to minimum t_next - xdevs::aux::Component::set_t_last(self, t); - xdevs::aux::Component::set_t_next(self, t_next); + xdevs::traits::Component::set_t_last(self, t); + xdevs::traits::Component::set_t_next(self, t_next); t_next } diff --git a/macros/src/component/port.rs b/macros/src/component/port.rs index ebcda36..37387b2 100644 --- a/macros/src/component/port.rs +++ b/macros/src/component/port.rs @@ -76,7 +76,7 @@ impl Ports { Self { #(#ports_ident: xdevs::port::Port::new()),* } } } - unsafe impl xdevs::aux::Bag for #ident { + unsafe impl xdevs::traits::Bag for #ident { #[inline] fn is_empty(&self) -> bool { true #( && self.#ports_ident.is_empty() )* diff --git a/src/lib.rs b/src/lib.rs index 7fca0b9..a3fc95a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,12 +2,12 @@ pub use xdevs_no_std_macros::*; -pub mod aux; +pub mod traits; pub mod port; pub mod simulator; /// Interface for DEVS atomic models. All DEVS atomic models must implement this trait. -pub trait Atomic: aux::PartialAtomic { +pub trait Atomic: traits::PartialAtomic { /// Method for performing any operation before simulating. By default, it does nothing. #[allow(unused_variables)] #[inline] diff --git a/src/port.rs b/src/port.rs index 6c2c633..a62d2a6 100644 --- a/src/port.rs +++ b/src/port.rs @@ -55,7 +55,7 @@ impl Port { } } -unsafe impl crate::aux::Bag for Port { +unsafe impl crate::traits::Bag for Port { fn is_empty(&self) -> bool { self.is_empty() } diff --git a/src/simulator.rs b/src/simulator.rs index 18c7abd..ae13adb 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -1,4 +1,4 @@ -use crate::aux::{AbstractSimulator, Bag}; +use crate::traits::{AbstractSimulator, Bag}; #[cfg(feature = "std")] pub mod std; diff --git a/src/simulator/std.rs b/src/simulator/std.rs index 83b2491..9134042 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -3,7 +3,7 @@ use std::time::{Duration, SystemTime}; /// Closure for RT simulation on targets with `std`. /// It sleeps until the next state transition. -pub fn sleep( +pub fn sleep( t_start: f64, time_scale: f64, max_jitter: Option, diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..facc66d --- /dev/null +++ b/src/traits.rs @@ -0,0 +1,96 @@ +/// Trait that defines the methods that a DEVS event bag set must implement. +/// +/// # Safety +/// +/// This trait must be implemented via macros. Do not implement it manually. +pub unsafe trait Bag { + /// Returns `true` if the ports are empty. + fn is_empty(&self) -> bool; + + /// Clears the ports, removing all values. + fn clear(&mut self); +} + +/// Interface for DEVS components. All DEVS components must implement this trait. +/// +/// # Safety +/// +/// This trait must be implemented via macros. Do not implement it manually. +pub unsafe trait Component { + /// Input event bag of the model. + type Input: Bag; + + /// Output event bag of the model. + type Output: Bag; + + /// Returns the last time the component was updated. + fn get_t_last(&self) -> f64; + + /// Sets the last time the component was updated. + fn set_t_last(&mut self, t_last: f64); + + /// Returns the next time the component will be updated. + fn get_t_next(&self) -> f64; + + /// Sets the next time the component will be updated. + fn set_t_next(&mut self, t_next: f64); + + /// Returns a reference to the model's input event bag. + fn get_input(&self) -> &Self::Input; + + /// Returns a mutable reference to the model's input event bag. + fn get_input_mut(&mut self) -> &mut Self::Input; + + /// Returns a reference to the model's output event bag. + fn get_output(&self) -> &Self::Output; + + /// Returns a mutable reference to the model's output event bag. + fn get_output_mut(&mut self) -> &mut Self::Output; + + /// Clears the input bag, removing all values. + #[inline] + fn clear_input(&mut self) { + self.get_input_mut().clear() + } + + /// Clears the output bag, removing all values. + #[inline] + fn clear_output(&mut self) { + self.get_output_mut().clear() + } +} + +/// Partial interface for DEVS atomic models. +/// It is used as a helper trait to implement the [`crate::Atomic`] trait. +/// +/// # Safety +/// +/// This trait must be implemented via macros. Do not implement it manually. +pub unsafe trait PartialAtomic: Component { + /// The data type used to represent the state of the model. + type State; +} + +/// Interface for simulating DEVS models. All DEVS models must implement this trait. +/// +/// # Safety +/// +/// This trait must be implemented via macros. Do not implement it manually. +pub unsafe trait AbstractSimulator: Component { + /// It starts the simulation, setting the initial time to t_start. + /// It returns the time for the next state transition of the inner DEVS model. + fn start(&mut self, t_start: f64) -> f64; + + /// It stops the simulation, setting the last time to t_stop. + fn stop(&mut self, t_stop: f64); + + /// Executes output functions and propagates messages according to EOCs. + /// Internally, it checks that the model is imminent before executing. + fn lambda(&mut self, t: f64); + + /// Propagates messages according to ICs and EICs and executes model transition functions. + /// It also clears all the input and output ports. + /// Internally, it checks that the model is imminent before executing. + /// Finally, it returns the time for the next state transition of the inner DEVS model. + fn delta(&mut self, t: f64) -> f64; +} \ No newline at end of file From 0b64a363f1e1582fdf41cffab3ec22ea6cf0b9c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 3 Apr 2024 14:56:49 +0200 Subject: [PATCH 3/8] Update traits.rs --- src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traits.rs b/src/traits.rs index facc66d..a1b6b37 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -93,4 +93,4 @@ pub unsafe trait AbstractSimulator: Component { /// Internally, it checks that the model is imminent before executing. /// Finally, it returns the time for the next state transition of the inner DEVS model. fn delta(&mut self, t: f64) -> f64; -} \ No newline at end of file +} From 02141c6462513e96d15371104c9700b78090ec98 Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Mon, 1 Jul 2024 19:23:16 +0200 Subject: [PATCH 4/8] Add wait_event --- src/simulator/std.rs | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/simulator/std.rs b/src/simulator/std.rs index 9134042..5c1e33b 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -1,5 +1,5 @@ extern crate std; -use std::time::{Duration, SystemTime}; +use std::{cmp, time::{Duration, SystemTime}}; /// Closure for RT simulation on targets with `std`. /// It sleeps until the next state transition. @@ -29,3 +29,62 @@ pub fn sleep( t_next } } + +/// Closure for waiting for an event in real-time simulation. +/// It calculates the next real-time and virtual-time based on the given time scale and sleeps until the next state transition. +/// If the maximum jitter is provided, it checks if the actual time exceeds the future time and panics if it does. +/// It also calls the input handler function with the duration between the current and next real-time. +/// +/// # Arguments +/// +/// * `t_start` - The starting virtual time. +/// * `time_scale` - The time scale factor. +/// * `max_jitter` - The maximum allowed jitter duration. +/// * `input_handler` - The function to handle the input event. +/// +/// # Returns +/// +/// A closure that takes the next virtual time and a mutable reference to the bag and returns the next virtual time. +pub fn wait_event( + t_start: f64, + time_scale: f64, + max_jitter: Option, + mut input_handler: impl FnMut(Duration, &mut T), +) -> impl FnMut(f64, &mut T) -> f64 { + + let mut last_vt = t_start; + let mut last_rt = SystemTime::now(); + let start_rt = last_rt; + + move |t_next, binput: &mut T| -> f64 { + + if t_next < last_vt { + panic!("Virtual time higher than t_next"); + } + let next_rt = last_rt + Duration::from_secs_f64((t_next - last_vt) * time_scale); + match next_rt.duration_since(SystemTime::now()) { + Ok(duration) => input_handler(duration, binput), + Err(err) => { + if let Some(max_jitter) = max_jitter { + // println!("Hay Jitter: {:?}", err.duration()); + if err.duration() > max_jitter { + panic!("Jitter too high"); + } + } + } + } + let t = SystemTime::now(); + + // Update time + last_rt = cmp::min(next_rt, t); + + if t < next_rt { + let duration_from_str = last_rt.duration_since(start_rt).unwrap(); + last_vt = duration_from_str.as_secs_f64() / time_scale; + }else { + last_vt = t_next; + } + last_vt + + } +} \ No newline at end of file From 1568efea0df9d92fd46a393d0fa8c233d678bd0b Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Wed, 3 Jul 2024 10:39:28 +0200 Subject: [PATCH 5/8] Improved wait_event function --- src/simulator/std.rs | 124 ++++++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 43 deletions(-) diff --git a/src/simulator/std.rs b/src/simulator/std.rs index 5c1e33b..3fe1c00 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -1,5 +1,6 @@ extern crate std; -use std::{cmp, time::{Duration, SystemTime}}; +use std::time::{Duration, SystemTime}; + /// Closure for RT simulation on targets with `std`. /// It sleeps until the next state transition. @@ -25,31 +26,59 @@ pub fn sleep( } last_vt = t_next; last_rt = next_rt; - t_next } } - -/// Closure for waiting for an event in real-time simulation. -/// It calculates the next real-time and virtual-time based on the given time scale and sleeps until the next state transition. -/// If the maximum jitter is provided, it checks if the actual time exceeds the future time and panics if it does. -/// It also calls the input handler function with the duration between the current and next real-time. /// -/// # Arguments -/// -/// * `t_start` - The starting virtual time. -/// * `time_scale` - The time scale factor. -/// * `max_jitter` - The maximum allowed jitter duration. -/// * `input_handler` - The function to handle the input event. +/// Default input handler function it only waits for a given time. +/// No Input Handler is specify. +/// +fn ihandler_default(waiting_period: std::time::Duration, _: &mut T) { + std::thread::sleep(waiting_period); +} + /// -/// # Returns +/// It computes the next wall-clock time corresponding to the next state transition of the model. +/// An input handler function waits for external events without exceeding the time for the next internal event. +/// Finally, it checks that the wall-clock drift does not exceed the maximum jitter allowed (if any) and panics if it does. +/// +/// # Arguments +/// +/// * `t_start` - The virtual time at the beginning of the simulation. +/// * `time_scale` - The time scale factor between virtual and wall-clock time. +/// * `max_jitter` - The maximum allowed jitter duration. If `None`, no jitter check is performed. +/// * `input_handler` - An optional function to handle incoming external events. The default value (i.e. not handling incoming events) is `ihandler_default`. +/// However, If provided, this function expects two arguments: +/// - `duration: [`Duration`]` - Maximum duration of the time interval to wait for external events. +/// The input handler function may return earlier if an input event is received. +/// Note, however, that it must **NOT** return after, as it would result in an incorrect real-time implementation. +/// - `input_ports: &mut T` - Mutable references to the input ports of the top-most model under simulation. +/// +/// # Returns /// -/// A closure that takes the next virtual time and a mutable reference to the bag and returns the next virtual time. +/// A closure that takes the next virtual time and a mutable reference to the bag and returns the next virtual time. +/// +/// # Example +/// +/// * Default implementation: +/// ```rust +/// +/// xdevs::simulator::std::wait_event(0.0, 1.0, Some(std::time::Duration::from_millis(100)), None:: ()>), +/// +/// ``` +/// +/// * Custom implementation: +/// +/// ```rust +/// +/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), Some(some_input_handler))), +/// +/// ``` pub fn wait_event( t_start: f64, time_scale: f64, max_jitter: Option, - mut input_handler: impl FnMut(Duration, &mut T), + mut input_handler: Option, ) -> impl FnMut(f64, &mut T) -> f64 { let mut last_vt = t_start; @@ -57,34 +86,43 @@ pub fn wait_event( let start_rt = last_rt; move |t_next, binput: &mut T| -> f64 { - - if t_next < last_vt { - panic!("Virtual time higher than t_next"); - } + + assert!(t_next >= last_vt); + let next_rt = last_rt + Duration::from_secs_f64((t_next - last_vt) * time_scale); - match next_rt.duration_since(SystemTime::now()) { - Ok(duration) => input_handler(duration, binput), - Err(err) => { - if let Some(max_jitter) = max_jitter { - // println!("Hay Jitter: {:?}", err.duration()); - if err.duration() > max_jitter { - panic!("Jitter too high"); - } - } + + + if let Ok(duration) = next_rt.duration_since(SystemTime::now()) { + if let Some(ref mut handler) = input_handler { + // Custom Input Handler + handler(duration, binput); + } else { + // Default Input Handler + ihandler_default(duration, binput); } - } - let t = SystemTime::now(); - - // Update time - last_rt = cmp::min(next_rt, t); - - if t < next_rt { - let duration_from_str = last_rt.duration_since(start_rt).unwrap(); - last_vt = duration_from_str.as_secs_f64() / time_scale; - }else { - last_vt = t_next; - } - last_vt - + } + + let t = SystemTime::now(); + + last_vt = match t.duration_since(next_rt) { + Ok(duration) => { // t >= next_rt + if let Some(max_jitter) = max_jitter { + if duration > max_jitter { + panic!("[WE]>> Jitter too high: {:?}", duration); + } + } + last_rt = next_rt; + t_next + + }, + Err(_) => { // t < next_rt + last_rt = t; + let duration = last_rt.duration_since(start_rt).unwrap(); + duration.as_secs_f64() / time_scale + } + }; + + last_vt + } } \ No newline at end of file From ff2166374d9d18abb0642ae72fb93270fb7d9ff5 Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Wed, 3 Jul 2024 11:34:38 +0200 Subject: [PATCH 6/8] Format --- src/simulator/std.rs | 92 +++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/src/simulator/std.rs b/src/simulator/std.rs index 3fe1c00..81a4ca3 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -1,7 +1,6 @@ extern crate std; use std::time::{Duration, SystemTime}; - /// Closure for RT simulation on targets with `std`. /// It sleeps until the next state transition. pub fn sleep( @@ -29,100 +28,87 @@ pub fn sleep( t_next } } -/// -/// Default input handler function it only waits for a given time. -/// No Input Handler is specify. -/// -fn ihandler_default(waiting_period: std::time::Duration, _: &mut T) { - std::thread::sleep(waiting_period); -} /// /// It computes the next wall-clock time corresponding to the next state transition of the model. +/// /// An input handler function waits for external events without exceeding the time for the next internal event. /// Finally, it checks that the wall-clock drift does not exceed the maximum jitter allowed (if any) and panics if it does. -/// +/// /// # Arguments -/// +/// /// * `t_start` - The virtual time at the beginning of the simulation. /// * `time_scale` - The time scale factor between virtual and wall-clock time. /// * `max_jitter` - The maximum allowed jitter duration. If `None`, no jitter check is performed. -/// * `input_handler` - An optional function to handle incoming external events. The default value (i.e. not handling incoming events) is `ihandler_default`. -/// However, If provided, this function expects two arguments: +/// * `input_handler` - An optional function to handle incoming external events. If provided, this function expects two arguments: /// - `duration: [`Duration`]` - Maximum duration of the time interval to wait for external events. -/// The input handler function may return earlier if an input event is received. -/// Note, however, that it must **NOT** return after, as it would result in an incorrect real-time implementation. +/// The input handler function may return earlier if an input event is received. +/// Note, however, that it must **NOT** return after, as it would result in an incorrect real-time implementation. /// - `input_ports: &mut T` - Mutable references to the input ports of the top-most model under simulation. /// /// # Returns /// /// A closure that takes the next virtual time and a mutable reference to the bag and returns the next virtual time. -/// +/// /// # Example -/// +/// /// * Default implementation: -/// ```rust -/// -/// xdevs::simulator::std::wait_event(0.0, 1.0, Some(std::time::Duration::from_millis(100)), None:: ()>), -/// +/// ```ignore +/// xdevs::simulator::std::wait_event(0.0, 1.0, Some(std::time::Duration::from_millis(100)), None:: ()>); /// ``` -/// +/// /// * Custom implementation: -/// -/// ```rust -/// -/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), Some(some_input_handler))), -/// +/// +/// ```ignore +/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), Some(some_input_handler))); /// ``` + pub fn wait_event( t_start: f64, time_scale: f64, - max_jitter: Option, + max_jitter: Option, mut input_handler: Option, ) -> impl FnMut(f64, &mut T) -> f64 { - let mut last_vt = t_start; let mut last_rt = SystemTime::now(); let start_rt = last_rt; move |t_next, binput: &mut T| -> f64 { - - assert!(t_next >= last_vt); + assert!(t_next >= last_vt); let next_rt = last_rt + Duration::from_secs_f64((t_next - last_vt) * time_scale); - - if let Ok(duration) = next_rt.duration_since(SystemTime::now()) { + if let Ok(duration) = next_rt.duration_since(SystemTime::now()) { if let Some(ref mut handler) = input_handler { // Custom Input Handler handler(duration, binput); } else { // Default Input Handler - ihandler_default(duration, binput); + std::thread::sleep(duration); } - } + } - let t = SystemTime::now(); + let t = SystemTime::now(); - last_vt = match t.duration_since(next_rt) { - Ok(duration) => { // t >= next_rt - if let Some(max_jitter) = max_jitter { - if duration > max_jitter { - panic!("[WE]>> Jitter too high: {:?}", duration); - } - } - last_rt = next_rt; - t_next - - }, - Err(_) => { // t < next_rt - last_rt = t; - let duration = last_rt.duration_since(start_rt).unwrap(); - duration.as_secs_f64() / time_scale - } + last_vt = match t.duration_since(next_rt) { + Ok(duration) => { + // t >= next_rt, check for the jitter + if let Some(max_jitter) = max_jitter { + if duration > max_jitter { + panic!("[WE]>> Jitter too high: {:?}", duration); + } + } + last_rt = next_rt; + t_next + } + Err(_) => { + // t < next_rt + last_rt = t; + let duration = last_rt.duration_since(start_rt).unwrap(); + duration.as_secs_f64() / time_scale + } }; last_vt - } -} \ No newline at end of file +} From e68947fd87026368738e9add5c2205bc4dc16077 Mon Sep 17 00:00:00 2001 From: OscarFdezS Date: Wed, 3 Jul 2024 12:18:59 +0200 Subject: [PATCH 7/8] Removed IH as an Option and Sleep implemented with wait_event --- src/simulator/std.rs | 47 +++++++++----------------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/src/simulator/std.rs b/src/simulator/std.rs index 81a4ca3..d1cdb3a 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -8,25 +8,9 @@ pub fn sleep( time_scale: f64, max_jitter: Option, ) -> impl FnMut(f64, &mut T) -> f64 { - let mut last_vt = t_start; - let mut last_rt = SystemTime::now(); - - move |t_next, _| -> f64 { - let next_rt = last_rt + Duration::from_secs_f64((t_next - last_vt) * time_scale); - match next_rt.duration_since(SystemTime::now()) { - Ok(duration) => std::thread::sleep(duration), - Err(err) => { - if let Some(max_jitter) = max_jitter { - if err.duration() > max_jitter { - panic!("Jitter too high"); - } - } - } - } - last_vt = t_next; - last_rt = next_rt; - t_next - } + wait_event(t_start, time_scale, max_jitter, |waiting_period, _| { + std::thread::sleep(waiting_period) + }) } /// @@ -40,11 +24,11 @@ pub fn sleep( /// * `t_start` - The virtual time at the beginning of the simulation. /// * `time_scale` - The time scale factor between virtual and wall-clock time. /// * `max_jitter` - The maximum allowed jitter duration. If `None`, no jitter check is performed. -/// * `input_handler` - An optional function to handle incoming external events. If provided, this function expects two arguments: -/// - `duration: [`Duration`]` - Maximum duration of the time interval to wait for external events. +/// * `input_handler` - The function to handle incoming external events. This function expects two arguments: +/// - `duration: [Duration]` - Maximum duration of the time interval to wait for external events. /// The input handler function may return earlier if an input event is received. /// Note, however, that it must **NOT** return after, as it would result in an incorrect real-time implementation. -/// - `input_ports: &mut T` - Mutable references to the input ports of the top-most model under simulation. +/// - `input_ports: &mut T` - Mutable reference to the input ports of the top-most model under simulation. /// /// # Returns /// @@ -52,22 +36,15 @@ pub fn sleep( /// /// # Example /// -/// * Default implementation: /// ```ignore -/// xdevs::simulator::std::wait_event(0.0, 1.0, Some(std::time::Duration::from_millis(100)), None:: ()>); -/// ``` -/// -/// * Custom implementation: -/// -/// ```ignore -/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), Some(some_input_handler))); +/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), some_input_handler); /// ``` pub fn wait_event( t_start: f64, time_scale: f64, max_jitter: Option, - mut input_handler: Option, + mut input_handler: impl FnMut(Duration, &mut T), ) -> impl FnMut(f64, &mut T) -> f64 { let mut last_vt = t_start; let mut last_rt = SystemTime::now(); @@ -79,13 +56,7 @@ pub fn wait_event( let next_rt = last_rt + Duration::from_secs_f64((t_next - last_vt) * time_scale); if let Ok(duration) = next_rt.duration_since(SystemTime::now()) { - if let Some(ref mut handler) = input_handler { - // Custom Input Handler - handler(duration, binput); - } else { - // Default Input Handler - std::thread::sleep(duration); - } + input_handler(duration, binput); } let t = SystemTime::now(); From 78d6385ca11c6f6a8a038d8e2b1420ad818f7fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 3 Jul 2024 12:23:09 +0200 Subject: [PATCH 8/8] Apply suggestions from code review --- src/simulator/std.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/simulator/std.rs b/src/simulator/std.rs index d1cdb3a..42a4424 100644 --- a/src/simulator/std.rs +++ b/src/simulator/std.rs @@ -13,7 +13,6 @@ pub fn sleep( }) } -/// /// It computes the next wall-clock time corresponding to the next state transition of the model. /// /// An input handler function waits for external events without exceeding the time for the next internal event.