use alloc::vec::Vec;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
use syunit::*;
use crate::{ActuatorError, InterruptReason, Interruptible, SyncActuatorBlocking};
mod endstop;
pub use endstop::*;
pub trait Measurable<V> {
type Error;
fn measure(&mut self) -> Result<V, Self::Error>;
}
pub enum SimpleMeasError<U : UnitSet> {
NoInterrupt,
WrongInterruptReason(InterruptReason),
SyncActuatorError(ActuatorError<U>)
}
impl<U : UnitSet> From<ActuatorError<U>> for SimpleMeasError<U> {
fn from(value: ActuatorError<U>) -> Self {
SimpleMeasError::SyncActuatorError(value)
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SimpleMeasParams<U : UnitSet> {
pub overwrite_abs_pos : U::Position,
pub max_dist : U::Distance,
pub meas_speed : Factor,
_add_samples : Option<usize>,
pub sample_dist : Option<U::Distance>
}
impl<U : UnitSet> SimpleMeasParams<U> {
pub fn add_samples(&self) -> usize {
self._add_samples.unwrap_or(1)
}
}
#[derive(Debug, Clone, Default)]
pub struct SimpleMeasValues<U : UnitSet> {
pub sample_count : usize,
pub positions : Vec<U::Position>,
pub position_avg : U::Position,
pub correction : U::Distance
}
impl<U : UnitSet> SimpleMeasValues<U> {
pub fn abs_pos_max(&self) -> U::Position {
*self.positions.iter().reduce(U::Position::max_ref).expect("Position array must contain a value")
}
pub fn abs_pos_min(&self) -> U::Position {
*self.positions.iter().reduce(U::Position::min_ref).expect("Position array must contain a value")
}
pub fn max_inacc(&self) -> U::Distance {
self.abs_pos_max() - self.abs_pos_min()
}
}
pub fn take_simple_meas<U : UnitSet, C : SyncActuatorBlocking<U> + Interruptible<U> + ?Sized>(comp : &mut C, data : &SimpleMeasParams<U>, speed : Factor) -> Result<SimpleMeasValues<U>, SimpleMeasError<U>> {
let mut abs_poss : Vec<U::Position> = Vec::new();
comp.drive_rel_blocking(data.max_dist, data.meas_speed * speed)?;
comp.intr_reason() .ok_or(SimpleMeasError::NoInterrupt)
.and_then(|reason|
if reason == InterruptReason::EndReached { Ok(()) } else { Err(SimpleMeasError::WrongInterruptReason(reason)) }
)?;
abs_poss.push(comp.pos());
for _ in 0 .. data.add_samples() {
comp.drive_rel_blocking(-data.sample_dist.unwrap_or(data.max_dist * 0.25) / 2.0, speed)?;
comp.drive_rel_blocking(data.sample_dist.unwrap_or(data.max_dist * 0.25), data.meas_speed * speed)?;
comp.intr_reason() .ok_or(SimpleMeasError::NoInterrupt)
.and_then(|reason|
if reason == InterruptReason::EndReached { Ok(()) } else { Err(SimpleMeasError::WrongInterruptReason(reason)) }
)?;
abs_poss.push(comp.pos());
}
let abs_pos_av = U::Position::from(abs_poss.iter().map(|g| (*g).into()).sum()) / (abs_poss.len() as f32);
let abs_pos_diff = comp.pos() - abs_pos_av;
let abs_pos_new = data.overwrite_abs_pos + abs_pos_diff;
comp.set_endpos(abs_pos_av);
comp.overwrite_abs_pos(abs_pos_new);
Ok(SimpleMeasValues {
sample_count: data.add_samples(),
positions: abs_poss,
position_avg: abs_pos_av,
correction: abs_pos_diff
})
}