Skip to content

Commit

Permalink
Merge branch 'main' of github.com:iscar-ucm/xdevs_no_std.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
romancardenas committed Jul 3, 2024
2 parents c8aab7c + e62c0e2 commit 84a93e0
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 45 deletions.
2 changes: 1 addition & 1 deletion macros/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
28 changes: 14 additions & 14 deletions macros/src/component/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
<Self as xdevs::Atomic>::start(&mut self.state);
let t_next = t_start + <Self as xdevs::Atomic>::ta(&self.state);
xdevs::aux::Component::set_t_next(self, t_next);
xdevs::traits::Component::set_t_next(self, t_next);

t_next
}
Expand All @@ -57,42 +57,42 @@ impl State {
// stop state
<Self as xdevs::Atomic>::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
<Self as xdevs::Atomic>::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
<Self as xdevs::Atomic>::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);
<Self as xdevs::Atomic>::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
<Self as xdevs::Atomic>::delta_int(&mut self.state);
} else {
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 + <Self as xdevs::Atomic>::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
}
Expand Down
28 changes: 14 additions & 14 deletions macros/src/component/coupled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,34 @@ 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
}

#[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);*
}
Expand All @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion macros/src/component/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() )*
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl<T: Clone, const N: usize> Port<T, N> {
}
}

unsafe impl<T: Clone, const N: usize> crate::aux::Bag for Port<T, N> {
unsafe impl<T: Clone, const N: usize> crate::traits::Bag for Port<T, N> {
fn is_empty(&self) -> bool {
self.is_empty()
}
Expand Down
2 changes: 1 addition & 1 deletion src/simulator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::aux::{AbstractSimulator, Bag};
use crate::traits::{AbstractSimulator, Bag};

#[cfg(feature = "std")]
pub mod std;
Expand Down
75 changes: 64 additions & 11 deletions src/simulator/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,82 @@ use std::time::{Duration, SystemTime};

/// Closure for RT simulation on targets with `std`.
/// It sleeps until the next state transition.
pub fn sleep<T: crate::aux::Bag>(
pub fn sleep<T: crate::traits::Bag>(
t_start: f64,
time_scale: f64,
max_jitter: Option<std::time::Duration>,
) -> impl FnMut(f64, &mut T) -> f64 {
wait_event(t_start, time_scale, max_jitter, |waiting_period, _| {
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` - 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 reference 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
///
/// ```ignore
/// xdevs::simulator::std::wait_event(0., 1., Some(Duration::from_millis(50)), some_input_handler);
/// ```
pub fn wait_event<T: crate::traits::Bag>(
t_start: f64,
time_scale: f64,
max_jitter: Option<Duration>,
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 {
assert!(t_next >= last_vt);

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 Ok(duration) = next_rt.duration_since(SystemTime::now()) {
input_handler(duration, binput);
}

let t = SystemTime::now();

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 err.duration() > max_jitter {
panic!("Jitter too high");
if duration > max_jitter {
panic!("[WE]>> Jitter too high: {:?}", duration);
}
}
last_rt = next_rt;
t_next
}
}
last_vt = t_next;
last_rt = next_rt;
Err(_) => {
// t < next_rt
last_rt = t;
let duration = last_rt.duration_since(start_rt).unwrap();
duration.as_secs_f64() / time_scale
}
};

t_next
last_vt
}
}
File renamed without changes.

0 comments on commit 84a93e0

Please sign in to comment.