use crate::calibration::{self, Calibration, CalibrationData, Point};
pub const DEFAULT_FREQUENCY: f32 = 50.0;
pub const MIN_FREQUENCY: f32 = 10.0;
pub const MAX_FREQUENCY: f32 = 350.0;
const MIN_VALID_PULSE: f32 = 1.0;
pub struct ServoState<C> {
servo_value: f32,
last_enabled_pulse: Option<f32>,
enabled: bool,
calibration: Calibration<C>,
}
impl<C> ServoState<C>
where
C: Default + Clone + CalibrationData,
{
pub fn new() -> Option<Self> {
Some(Self {
servo_value: 0.0,
last_enabled_pulse: None,
enabled: false,
calibration: Calibration::new()?,
})
}
}
impl<C> ServoState<C>
where
C: CalibrationData,
for<'a> <C as CalibrationData>::Iterator<'a>: Iterator<Item = (Point, Point)>,
{
pub fn with_calibration(calibration: Calibration<C>) -> Self {
Self {
servo_value: 0.0,
last_enabled_pulse: None,
enabled: false,
calibration,
}
}
pub fn enable_with_return(&mut self) -> f32 {
if let Some(pulse) = self.last_enabled_pulse {
self.enabled = true;
pulse
} else {
self.go_to_mid_with_return()
}
}
#[inline]
fn go_to_mid_with_return(&mut self) -> f32 {
self.set_value_with_return(self.calibration.mid_value())
}
#[inline]
fn inner_enable_with_return(&mut self) -> Option<f32> {
self.enabled = true;
self.last_enabled_pulse
}
pub fn set_value_with_return(&mut self, value: f32) -> f32 {
let point = self.calibration.value_to_pulse(value);
self.last_enabled_pulse = Some(point.pulse);
self.servo_value = point.value;
self.enabled = true;
point.pulse
}
#[inline]
pub fn disable(&mut self) {
self.enabled = false;
}
#[inline]
pub fn enabled(&self) -> bool {
self.enabled
}
pub fn pulse_to_level(pulse: f32, resolution: u32, frequency: f32) -> u32 {
if pulse >= MIN_VALID_PULSE {
((pulse * resolution as f32 * frequency) as u64 / 1_000_000) as u32
} else {
0
}
}
#[inline]
pub fn pulse(&self) -> Option<f32> {
self.last_enabled_pulse
}
pub fn set_pulse_with_return(&mut self, pulse: f32) -> Option<f32> {
if pulse >= MIN_VALID_PULSE {
if let Some(point) = self.calibration.pulse_to_value(pulse) {
self.servo_value = point.value;
self.last_enabled_pulse = Some(point.pulse);
return self.inner_enable_with_return();
}
}
self.disable();
None
}
#[inline]
pub fn value(&self) -> f32 {
self.servo_value
}
#[inline]
pub(crate) fn min_value(&self) -> f32 {
self.calibration.first().value
}
#[inline]
pub(crate) fn mid_value(&self) -> f32 {
self.calibration.mid_value()
}
#[inline]
pub(crate) fn max_value(&self) -> f32 {
self.calibration.last().value
}
#[inline]
pub fn to_min_with_return(&mut self) -> f32 {
self.set_value_with_return(self.min_value())
}
#[inline]
pub fn to_mid_with_return(&mut self) -> f32 {
self.set_value_with_return(self.mid_value())
}
#[inline]
pub fn to_max_with_return(&mut self) -> f32 {
self.set_value_with_return(self.max_value())
}
pub fn to_percent_with_return(&mut self, percent: f32) -> f32 {
let value = calibration::map_float(percent, 0.0, 100.0, self.min_value(), self.max_value());
self.set_value_with_return(value)
}
#[inline]
pub fn calibration(&self) -> &Calibration<C> {
&self.calibration
}
#[inline]
pub fn calibration_mut(&mut self) -> &mut Calibration<C> {
&mut self.calibration
}
}