forked from ROMEO/nexosim
Make execution failible, impl deadlock detection
TODO: return the list of models involved in a deadlock. Note that Many execution errors are not implemented at all at the moment and will need separate PRs, namely: - Terminated - ModelError - Panic
This commit is contained in:
@ -25,7 +25,7 @@ use std::time::Duration;
|
||||
|
||||
use asynchronix::model::{Model, SetupContext};
|
||||
use asynchronix::ports::{EventBuffer, Output};
|
||||
use asynchronix::simulation::{Mailbox, SimInit};
|
||||
use asynchronix::simulation::{Mailbox, SimInit, SimulationError};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
|
||||
mod stepper_motor;
|
||||
@ -84,7 +84,7 @@ impl Model for MotorAssembly {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), SimulationError> {
|
||||
// ---------------
|
||||
// Bench assembly.
|
||||
// ---------------
|
||||
@ -107,7 +107,7 @@ fn main() {
|
||||
// Assembly and initialization.
|
||||
let mut simu = SimInit::new()
|
||||
.add_model(assembly, assembly_mbox, "assembly")
|
||||
.init(t0);
|
||||
.init(t0)?;
|
||||
|
||||
let scheduler = simu.scheduler();
|
||||
|
||||
@ -132,10 +132,10 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// Advance simulation time to two next events.
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(2, 0);
|
||||
assert_eq!(simu.time(), t);
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
|
||||
@ -147,7 +147,7 @@ fn main() {
|
||||
|
||||
// Advance simulation time by 0.9s, which with a 10Hz PPS should correspond to
|
||||
// 9 position increments.
|
||||
simu.step_by(Duration::new(0, 900_000_000));
|
||||
simu.step_by(Duration::new(0, 900_000_000))?;
|
||||
t += Duration::new(0, 900_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
for _ in 0..9 {
|
||||
@ -155,4 +155,6 @@ fn main() {
|
||||
assert_eq!(position.next(), Some(pos));
|
||||
}
|
||||
assert!(position.next().is_none());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ use std::time::Duration;
|
||||
|
||||
use asynchronix::model::{Context, InitializedModel, Model};
|
||||
use asynchronix::ports::{EventSlot, Output};
|
||||
use asynchronix::simulation::{ActionKey, Mailbox, SimInit};
|
||||
use asynchronix::simulation::{ActionKey, Mailbox, SimInit, SimulationError};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
|
||||
/// Water pump.
|
||||
@ -332,7 +332,7 @@ pub enum WaterSenseState {
|
||||
NotEmpty,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), SimulationError> {
|
||||
// ---------------
|
||||
// Bench assembly.
|
||||
// ---------------
|
||||
@ -375,7 +375,7 @@ fn main() {
|
||||
.add_model(controller, controller_mbox, "controller")
|
||||
.add_model(pump, pump_mbox, "pump")
|
||||
.add_model(tank, tank_mbox, "tank")
|
||||
.init(t0);
|
||||
.init(t0)?;
|
||||
|
||||
let scheduler = simu.scheduler();
|
||||
|
||||
@ -388,10 +388,10 @@ fn main() {
|
||||
assert_eq!(simu.time(), t);
|
||||
|
||||
// Brew one espresso shot with the default brew time.
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
assert_eq!(flow_rate.next(), Some(pump_flow_rate));
|
||||
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Controller::DEFAULT_BREW_TIME;
|
||||
assert_eq!(simu.time(), t);
|
||||
assert_eq!(flow_rate.next(), Some(0.0));
|
||||
@ -400,33 +400,33 @@ fn main() {
|
||||
let volume_per_shot = pump_flow_rate * Controller::DEFAULT_BREW_TIME.as_secs_f64();
|
||||
let shots_per_tank = (init_tank_volume / volume_per_shot) as u64; // YOLO--who cares about floating-point rounding errors?
|
||||
for _ in 0..(shots_per_tank - 1) {
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
assert_eq!(flow_rate.next(), Some(pump_flow_rate));
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Controller::DEFAULT_BREW_TIME;
|
||||
assert_eq!(simu.time(), t);
|
||||
assert_eq!(flow_rate.next(), Some(0.0));
|
||||
}
|
||||
|
||||
// Check that the tank becomes empty before the completion of the next shot.
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.step();
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
simu.step()?;
|
||||
assert!(simu.time() < t + Controller::DEFAULT_BREW_TIME);
|
||||
t = simu.time();
|
||||
assert_eq!(flow_rate.next(), Some(0.0));
|
||||
|
||||
// Try to brew another shot while the tank is still empty.
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
assert!(flow_rate.next().is_none());
|
||||
|
||||
// Change the brew time and fill up the tank.
|
||||
let brew_time = Duration::new(30, 0);
|
||||
simu.process_event(Controller::brew_time, brew_time, &controller_addr);
|
||||
simu.process_event(Tank::fill, 1.0e-3, tank_addr);
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.process_event(Controller::brew_time, brew_time, &controller_addr)?;
|
||||
simu.process_event(Tank::fill, 1.0e-3, tank_addr)?;
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
assert_eq!(flow_rate.next(), Some(pump_flow_rate));
|
||||
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += brew_time;
|
||||
assert_eq!(simu.time(), t);
|
||||
assert_eq!(flow_rate.next(), Some(0.0));
|
||||
@ -440,11 +440,13 @@ fn main() {
|
||||
&controller_addr,
|
||||
)
|
||||
.unwrap();
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr);
|
||||
simu.process_event(Controller::brew_cmd, (), &controller_addr)?;
|
||||
assert_eq!(flow_rate.next(), Some(pump_flow_rate));
|
||||
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::from_secs(15);
|
||||
assert_eq!(simu.time(), t);
|
||||
assert_eq!(flow_rate.next(), Some(0.0));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use mio::{Events, Interest, Poll, Token};
|
||||
|
||||
use asynchronix::model::{Context, InitializedModel, Model, SetupContext};
|
||||
use asynchronix::ports::{EventBuffer, Output};
|
||||
use asynchronix::simulation::{Mailbox, SimInit};
|
||||
use asynchronix::simulation::{Mailbox, SimInit, SimulationError};
|
||||
use asynchronix::time::{AutoSystemClock, MonotonicTime};
|
||||
|
||||
const DELTA: Duration = Duration::from_millis(2);
|
||||
@ -184,7 +184,7 @@ impl Drop for Listener {
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), SimulationError> {
|
||||
// ---------------
|
||||
// Bench assembly.
|
||||
// ---------------
|
||||
@ -210,7 +210,7 @@ fn main() {
|
||||
let mut simu = SimInit::new()
|
||||
.add_model(listener, listener_mbox, "listener")
|
||||
.set_clock(AutoSystemClock::new())
|
||||
.init(t0);
|
||||
.init(t0)?;
|
||||
|
||||
// ----------
|
||||
// Simulation.
|
||||
@ -231,7 +231,7 @@ fn main() {
|
||||
});
|
||||
|
||||
// Advance simulation, external messages will be collected.
|
||||
simu.step_by(Duration::from_secs(2));
|
||||
simu.step_by(Duration::from_secs(2))?;
|
||||
|
||||
// Check collected external messages.
|
||||
let mut packets = 0_u32;
|
||||
@ -244,4 +244,6 @@ fn main() {
|
||||
assert_eq!(message.next(), None);
|
||||
|
||||
sender_handle.join().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
//! ```
|
||||
use asynchronix::model::Model;
|
||||
use asynchronix::ports::{EventSlot, Output, Requestor};
|
||||
use asynchronix::simulation::{Mailbox, SimInit};
|
||||
use asynchronix::simulation::{Mailbox, SimInit, SimulationError};
|
||||
use asynchronix::time::MonotonicTime;
|
||||
|
||||
/// Power supply.
|
||||
@ -99,7 +99,7 @@ impl Load {
|
||||
|
||||
impl Model for Load {}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), SimulationError> {
|
||||
// ---------------
|
||||
// Bench assembly.
|
||||
// ---------------
|
||||
@ -144,7 +144,7 @@ fn main() {
|
||||
.add_model(load1, load1_mbox, "load1")
|
||||
.add_model(load2, load2_mbox, "load2")
|
||||
.add_model(load3, load3_mbox, "load3")
|
||||
.init(t0);
|
||||
.init(t0)?;
|
||||
|
||||
// ----------
|
||||
// Simulation.
|
||||
@ -158,7 +158,7 @@ fn main() {
|
||||
|
||||
// Vary the supply voltage, check the load and power supply consumptions.
|
||||
for voltage in [10.0, 15.0, 20.0] {
|
||||
simu.process_event(PowerSupply::voltage_setting, voltage, &psu_addr);
|
||||
simu.process_event(PowerSupply::voltage_setting, voltage, &psu_addr)?;
|
||||
|
||||
let v_square = voltage * voltage;
|
||||
assert!(same_power(load1_power.next().unwrap(), v_square / r1));
|
||||
@ -169,4 +169,6 @@ fn main() {
|
||||
v_square * (1.0 / r1 + 1.0 / r2 + 1.0 / r3)
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ impl Driver {
|
||||
impl Model for Driver {}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn main() {
|
||||
fn main() -> Result<(), asynchronix::simulation::SimulationError> {
|
||||
// ---------------
|
||||
// Bench assembly.
|
||||
// ---------------
|
||||
@ -235,7 +235,7 @@ fn main() {
|
||||
let mut simu = SimInit::new()
|
||||
.add_model(driver, driver_mbox, "driver")
|
||||
.add_model(motor, motor_mbox, "motor")
|
||||
.init(t0);
|
||||
.init(t0)?;
|
||||
|
||||
let scheduler = simu.scheduler();
|
||||
|
||||
@ -260,10 +260,10 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// Advance simulation time to two next events.
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(2, 0);
|
||||
assert_eq!(simu.time(), t);
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
|
||||
@ -275,7 +275,7 @@ fn main() {
|
||||
|
||||
// Advance simulation time by 0.9s, which with a 10Hz PPS should correspond to
|
||||
// 9 position increments.
|
||||
simu.step_by(Duration::new(0, 900_000_000));
|
||||
simu.step_by(Duration::new(0, 900_000_000))?;
|
||||
t += Duration::new(0, 900_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
for _ in 0..9 {
|
||||
@ -285,24 +285,24 @@ fn main() {
|
||||
assert!(position.next().is_none());
|
||||
|
||||
// Increase the load beyond the torque limit for a 1A driver current.
|
||||
simu.process_event(Motor::load, 2.0, &motor_addr);
|
||||
simu.process_event(Motor::load, 2.0, &motor_addr)?;
|
||||
|
||||
// Advance simulation time and check that the motor is blocked.
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
assert!(position.next().is_none());
|
||||
|
||||
// Do it again.
|
||||
simu.step();
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
assert!(position.next().is_none());
|
||||
|
||||
// Decrease the load below the torque limit for a 1A driver current and
|
||||
// advance simulation time.
|
||||
simu.process_event(Motor::load, 0.5, &motor_addr);
|
||||
simu.step();
|
||||
simu.process_event(Motor::load, 0.5, &motor_addr)?;
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
|
||||
// The motor should start moving again, but since the phase was incremented
|
||||
@ -314,7 +314,7 @@ fn main() {
|
||||
|
||||
// Advance simulation time by 0.7s, which with a 10Hz PPS should correspond to
|
||||
// 7 position increments.
|
||||
simu.step_by(Duration::new(0, 700_000_000));
|
||||
simu.step_by(Duration::new(0, 700_000_000))?;
|
||||
t += Duration::new(0, 700_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
for _ in 0..7 {
|
||||
@ -325,8 +325,8 @@ fn main() {
|
||||
|
||||
// Now make the motor rotate in the opposite direction. Note that this
|
||||
// driver only accounts for a new PPS at the next pulse.
|
||||
simu.process_event(Driver::pulse_rate, -10.0, &driver_addr);
|
||||
simu.step();
|
||||
simu.process_event(Driver::pulse_rate, -10.0, &driver_addr)?;
|
||||
simu.step()?;
|
||||
t += Duration::new(0, 100_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
pos = (pos + 1) % Motor::STEPS_PER_REV;
|
||||
@ -334,9 +334,11 @@ fn main() {
|
||||
|
||||
// Advance simulation time by 1.9s, which with a -10Hz PPS should correspond
|
||||
// to 19 position decrements.
|
||||
simu.step_by(Duration::new(1, 900_000_000));
|
||||
simu.step_by(Duration::new(1, 900_000_000))?;
|
||||
t += Duration::new(1, 900_000_000);
|
||||
assert_eq!(simu.time(), t);
|
||||
pos = (pos + Motor::STEPS_PER_REV - 19) % Motor::STEPS_PER_REV;
|
||||
assert_eq!(position.by_ref().last(), Some(pos));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user