Files
continuum-proxy/src/plate_changer/mod.rs
T
octoturge 9b3815fd25 Fix build errors: FTPS AsyncRead bridge, TLS connector type, unsafe env::set_var, dead code
Verified with cargo check + cargo run --example printer_polymorphism.
2026-08-28 17:09:11 +00:00

69 lines
2.2 KiB
Rust

mod gpio;
mod serial;
use thiserror::Error;
use tracing::{info, warn};
#[derive(Debug, Error)]
pub enum PlateChangerError {
#[error("plate changer hardware not responding")]
NotResponding,
#[error("sensor validation failed: {0}")]
SensorMismatch(String),
#[error("serial transport error: {0}")]
Serial(#[from] serial::SerialError),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CycleOutcome {
Success,
Retried,
}
/// Drives a mechanical plate-swap cycle: signal the changer over serial,
/// wait for it to report completion, then cross-check the physical sensors
/// (plate-present, bed-clear) before releasing the print queue to continue.
pub struct PlateChanger {
port: serial::SerialPort,
}
impl PlateChanger {
pub fn open(path: &str, baud: u32) -> Result<Self, PlateChangerError> {
Ok(Self {
port: serial::SerialPort::open(path, baud)?,
})
}
pub async fn run_cycle(&mut self, slot: u8) -> Result<CycleOutcome, PlateChangerError> {
info!(slot, "starting plate change cycle");
self.port.send_command(&serial::Command::Eject).await?;
self.port.await_ack(std::time::Duration::from_secs(30)).await?;
self.port.send_command(&serial::Command::LoadSlot(slot)).await?;
self.port.await_ack(std::time::Duration::from_secs(30)).await?;
match self.validate_sensors().await {
Ok(()) => Ok(CycleOutcome::Success),
Err(err) => {
warn!(?err, slot, "sensor validation failed, retrying cycle once");
self.port.send_command(&serial::Command::LoadSlot(slot)).await?;
self.port.await_ack(std::time::Duration::from_secs(30)).await?;
self.validate_sensors().await?;
Ok(CycleOutcome::Retried)
}
}
}
async fn validate_sensors(&mut self) -> Result<(), PlateChangerError> {
let state = gpio::read_sensor_state().await;
if !state.plate_present {
return Err(PlateChangerError::SensorMismatch("plate not detected on bed".into()));
}
if !state.bed_clear {
return Err(PlateChangerError::SensorMismatch("bed obstruction detected".into()));
}
Ok(())
}
}