1
0
forked from ROMEO/nexosim

Add setup step.

This commit is contained in:
Jaŭhien Piatlicki
2024-04-11 09:40:37 +02:00
parent e84e802f09
commit 7526ffbcea
23 changed files with 836 additions and 798 deletions

View File

@ -31,14 +31,12 @@
//! (-)
//! ```
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use asynchronix::model::{InitializedModel, Model};
use asynchronix::model::{Context, InitializedModel, Model};
use asynchronix::ports::{EventSlot, Output};
use asynchronix::simulation::{Mailbox, SimInit};
use asynchronix::time::{ActionKey, MonotonicTime, Scheduler};
use asynchronix::simulation::{ActionKey, Mailbox, SimInit};
use asynchronix::time::MonotonicTime;
/// Water pump.
pub struct Pump {
@ -122,7 +120,7 @@ impl Controller {
}
/// Starts brewing or cancels the current brew -- input port.
pub async fn brew_cmd(&mut self, _: (), scheduler: &Scheduler<Self>) {
pub async fn brew_cmd(&mut self, _: (), context: &Context<Self>) {
// If a brew was ongoing, sending the brew command is interpreted as a
// request to cancel it.
if let Some(key) = self.stop_brew_key.take() {
@ -141,7 +139,7 @@ impl Controller {
// Schedule the `stop_brew()` method and turn on the pump.
self.stop_brew_key = Some(
scheduler
context
.schedule_keyed_event(self.brew_time, Self::stop_brew, ())
.unwrap(),
);
@ -190,7 +188,7 @@ impl Tank {
}
/// Water volume added [m³] -- input port.
pub async fn fill(&mut self, added_volume: f64, scheduler: &Scheduler<Self>) {
pub async fn fill(&mut self, added_volume: f64, context: &Context<Self>) {
// Ignore zero and negative values. We could also impose a maximum based
// on tank capacity.
if added_volume <= 0.0 {
@ -208,11 +206,11 @@ impl Tank {
state.set_empty_key.cancel();
// Update the volume, saturating at 0 in case of rounding errors.
let time = scheduler.time();
let time = context.time();
let elapsed_time = time.duration_since(state.last_volume_update).as_secs_f64();
self.volume = (self.volume - state.flow_rate * elapsed_time).max(0.0);
self.schedule_empty(state.flow_rate, time, scheduler).await;
self.schedule_empty(state.flow_rate, time, context).await;
// There is no need to broadcast the state of the water sense since
// it could not be previously `Empty` (otherwise the dynamic state
@ -230,10 +228,10 @@ impl Tank {
/// # Panics
///
/// This method will panic if the flow rate is negative.
pub async fn set_flow_rate(&mut self, flow_rate: f64, scheduler: &Scheduler<Self>) {
pub async fn set_flow_rate(&mut self, flow_rate: f64, context: &Context<Self>) {
assert!(flow_rate >= 0.0);
let time = scheduler.time();
let time = context.time();
// If the flow rate was non-zero up to now, update the volume.
if let Some(state) = self.dynamic_state.take() {
@ -245,7 +243,7 @@ impl Tank {
self.volume = (self.volume - state.flow_rate * elapsed_time).max(0.0);
}
self.schedule_empty(flow_rate, time, scheduler).await;
self.schedule_empty(flow_rate, time, context).await;
}
/// Schedules a callback for when the tank becomes empty.
@ -258,7 +256,7 @@ impl Tank {
&mut self,
flow_rate: f64,
time: MonotonicTime,
scheduler: &Scheduler<Self>,
context: &Context<Self>,
) {
// Determine when the tank will be empty at the current flow rate.
let duration_until_empty = if self.volume == 0.0 {
@ -275,7 +273,7 @@ impl Tank {
let duration_until_empty = Duration::from_secs_f64(duration_until_empty);
// Schedule the next update.
match scheduler.schedule_keyed_event(duration_until_empty, Self::set_empty, ()) {
match context.schedule_keyed_event(duration_until_empty, Self::set_empty, ()) {
Ok(set_empty_key) => {
let state = TankDynamicState {
last_volume_update: time,
@ -302,21 +300,16 @@ impl Tank {
impl Model for Tank {
/// Broadcasts the initial state of the water sense.
fn init(
mut self,
_scheduler: &Scheduler<Self>,
) -> Pin<Box<dyn Future<Output = InitializedModel<Self>> + Send + '_>> {
Box::pin(async move {
self.water_sense
.send(if self.volume == 0.0 {
WaterSenseState::Empty
} else {
WaterSenseState::NotEmpty
})
.await;
async fn init(mut self, _: &Context<Self>) -> InitializedModel<Self> {
self.water_sense
.send(if self.volume == 0.0 {
WaterSenseState::Empty
} else {
WaterSenseState::NotEmpty
})
.await;
self.into()
})
self.into()
}
}

View File

@ -24,7 +24,7 @@
//! │ Power │ ◀current │ │
//! │ supply │ └────────┘
//! │ ├───────────────────────────────▶ Total power
//! └──────────┘
//! └──────────┘
//! ```
use asynchronix::model::Model;
use asynchronix::ports::{EventSlot, Output, Requestor};

View File

@ -15,13 +15,12 @@
//! ```
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;
use asynchronix::model::{InitializedModel, Model};
use asynchronix::model::{Context, InitializedModel, Model};
use asynchronix::ports::{EventBuffer, Output};
use asynchronix::simulation::{Mailbox, SimInit};
use asynchronix::time::{MonotonicTime, Scheduler};
use asynchronix::time::MonotonicTime;
/// Stepper motor.
pub struct Motor {
@ -88,15 +87,9 @@ impl Motor {
impl Model for Motor {
/// Broadcasts the initial position of the motor.
fn init(
mut self,
_scheduler: &Scheduler<Self>,
) -> Pin<Box<dyn Future<Output = InitializedModel<Self>> + Send + '_>> {
Box::pin(async move {
self.position.send(self.pos).await;
self.into()
})
async fn init(mut self, _: &Context<Self>) -> InitializedModel<Self> {
self.position.send(self.pos).await;
self.into()
}
}
@ -130,7 +123,7 @@ impl Driver {
}
/// Sets the pulse rate (sign = direction) [Hz] -- input port.
pub async fn pulse_rate(&mut self, pps: f64, scheduler: &Scheduler<Self>) {
pub async fn pulse_rate(&mut self, pps: f64, context: &Context<Self>) {
let pps = pps.signum() * pps.abs().clamp(Self::MIN_PPS, Self::MAX_PPS);
if pps == self.pps {
return;
@ -142,7 +135,7 @@ impl Driver {
// Trigger the rotation if the motor is currently idle. Otherwise the
// new value will be accounted for at the next pulse.
if is_idle {
self.send_pulse((), scheduler).await;
self.send_pulse((), context).await;
}
}
@ -153,7 +146,7 @@ impl Driver {
fn send_pulse<'a>(
&'a mut self,
_: (),
scheduler: &'a Scheduler<Self>,
context: &'a Context<Self>,
) -> impl Future<Output = ()> + Send + 'a {
async move {
let current_out = match self.next_phase {
@ -174,7 +167,7 @@ impl Driver {
let pulse_duration = Duration::from_secs_f64(1.0 / self.pps.abs());
// Schedule the next pulse.
scheduler
context
.schedule_event(pulse_duration, Self::send_pulse, ())
.unwrap();
}