pub mod fsm;
pub mod request;
pub mod timer;
mod lights;
mod self_elevator;
use crate::config;
use crate::elevio;
use crate::elevio::elev::Elevator;
use crate::elevio::ElevMessage;
use crate::print;
use crate::world_view;
use crate::world_view::Dirn;
use crate::world_view::ElevatorBehaviour;
use crate::world_view::ElevatorContainer;
use crate::world_view::WorldView;
use std::time::Duration;
use tokio::task::yield_now;
use tokio::sync::mpsc;
use tokio::sync::watch;
use tokio::time::sleep;
pub async fn run_local_elevator(
wv_watch_rx: watch::Receiver<WorldView>,
elevator_states_tx: mpsc::Sender<ElevatorContainer>
)
{
let (local_elev_tx, local_elev_rx) = mpsc::channel::<ElevMessage>(100);
let elevator = self_elevator::init(local_elev_tx).await;
{
let elevator_c = elevator.clone();
let wv_watch_rx_c = wv_watch_rx.clone();
tokio::spawn(async move
{
let _ = handle_elevator(wv_watch_rx_c, elevator_states_tx, local_elev_rx, elevator_c).await;
});
}
{ let e = elevator.clone();
let wv_watch_rx_c = wv_watch_rx.clone();
tokio::spawn(async move {
let mut wv = world_view::get_wv(wv_watch_rx);
loop
{
world_view::update_wv(wv_watch_rx_c.clone(), &mut wv).await;
match world_view::extract_self_elevator_container(&wv)
{
Some(cont) =>
{
lights::set_hall_lights(&wv, e.clone(), &cont);
}
None =>
{
print::warn(format!("Failed to extract self elevator container"));
}
}
sleep(config::POLL_PERIOD).await;
}
});
}
loop
{
yield_now().await;
}
}
async fn handle_elevator(
wv_watch_rx: watch::Receiver<WorldView>,
elevator_states_tx: mpsc::Sender<ElevatorContainer>,
mut local_elev_rx: mpsc::Receiver<elevio::ElevMessage>,
e: Elevator
)
{
let mut wv = world_view::get_wv(wv_watch_rx.clone());
let mut self_container = await_valid_self_container(wv_watch_rx.clone()).await;
let mut timers = timer::ElevatorTimers::new(
Duration::from_secs(3), Duration::from_secs(10), Duration::from_secs(7), );
fsm::on_init(&mut self_container, e.clone(), &mut local_elev_rx, &mut timers).await;
let mut prev_behavior: ElevatorBehaviour = self_container.behaviour;
let mut prev_floor: u8 = self_container.last_floor_sensor;
let mut prev_stop_btn: bool = self_container.stop;
loop
{
self_elevator::update_elev_container_from_msgs(
&mut local_elev_rx,
&mut self_container,
&mut timers.cab_priority ,
&mut timers.error
).await;
fsm::handle_idle_state(
&mut self_container,
e.clone(),
&mut timers.door
);
fsm::handle_floor_sensor_update(
&mut self_container,
e.clone(),
&mut prev_floor,
&mut timers,
).await;
fsm::handle_door_timeout(
&mut self_container,
e.clone(),
&timers.door,
&mut timers.cab_priority,
).await;
fsm::handle_stop_button(
&mut self_container,
e.clone(),
&mut prev_stop_btn
).await;
fsm::handle_error_timeout(
&self_container,
&timers.cab_priority,
&mut timers.error,
timers.prev_cab_priority_timeout,
);
sleep(config::POLL_PERIOD).await;
update_motor_direction_if_needed(&self_container, &e);
update_error_state(&mut self_container, &timers.error, &mut timers.prev_cab_priority_timeout, &prev_behavior);
let last_behavior: ElevatorBehaviour = track_behavior_change(&self_container, &mut prev_behavior);
stop_motor_on_dooropen_to_error(&mut self_container, last_behavior, prev_behavior);
self_container.last_behaviour = last_behavior;
if world_view::update_wv(wv_watch_rx.clone(), &mut wv).await
{
update_tasks_and_hall_requests(&mut self_container, &wv).await;
}
let _ = elevator_states_tx.send(self_container.clone()).await;
yield_now().await;
}
}
async fn update_tasks_and_hall_requests(
self_container: &mut ElevatorContainer,
wv: &WorldView
)
{
if let Some(task_container) = world_view::extract_self_elevator_container(wv)
{
self_container.tasks = task_container.tasks.clone();
self_container.cab_requests = task_container.cab_requests.clone();
self_container.unsent_hall_request = task_container.unsent_hall_request.clone();
} else
{
print::warn(format!("Failed to extract self elevator container – keeping previous value"));
}
}
async fn await_valid_self_container(
wv_rx: watch::Receiver<WorldView>
) -> ElevatorContainer
{
loop
{
let wv = world_view::get_wv(wv_rx.clone());
if let Some(container) = world_view::extract_self_elevator_container(&wv)
{
return container.clone();
} else
{
print::warn(format!("Failed to extract self elevator container, retrying..."));
sleep(Duration::from_millis(100)).await;
}
}
}
fn update_motor_direction_if_needed(
self_container: &ElevatorContainer,
e: &Elevator
)
{
if self_container.behaviour != ElevatorBehaviour::DoorOpen
{
e.motor_direction(self_container.dirn as u8);
}
}
fn update_error_state(
self_container: &mut ElevatorContainer,
error_timer: &timer::Timer,
prev_cab_priority_timer_stat: &mut bool,
prev_behavior: &ElevatorBehaviour,
)
{
if error_timer.timer_timeouted()
{
if was_prew_state_error(prev_behavior){ return;}
*prev_cab_priority_timer_stat = true;
if *prev_behavior == ElevatorBehaviour::DoorOpen
{
self_container.behaviour = ElevatorBehaviour::ObstructionError;
} else if *prev_behavior == ElevatorBehaviour::Moving
{
self_container.behaviour = ElevatorBehaviour::TravelError;
} else
{
self_container.behaviour = ElevatorBehaviour::CosmicError;
}
} else
{
*prev_cab_priority_timer_stat = false;
}
}
fn was_prew_state_error(
prev_behavior: &ElevatorBehaviour
) -> bool
{
*prev_behavior == ElevatorBehaviour::ObstructionError ||
*prev_behavior == ElevatorBehaviour::TravelError ||
*prev_behavior == ElevatorBehaviour::CosmicError
}
fn track_behavior_change(
self_container: &ElevatorContainer,
prev_behavior: &mut ElevatorBehaviour,
) -> ElevatorBehaviour
{
let last_behavior = *prev_behavior;
if *prev_behavior != self_container.behaviour
{
*prev_behavior = self_container.behaviour;
print::info(format!("Changed behaviour: {:?} -> {:?}", last_behavior, self_container.behaviour));
}
last_behavior
}
fn stop_motor_on_dooropen_to_error(
self_container: &mut ElevatorContainer,
last_behavior: ElevatorBehaviour,
current_behavior: ElevatorBehaviour,
)
{
if last_behavior == ElevatorBehaviour::DoorOpen && current_behavior == ElevatorBehaviour::ObstructionError
{
self_container.dirn = Dirn::Stop;
}
}