use crate::motor::MotorKind;
use ph_curves::{MonotonicCurveLut256, Rounding};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LoopMode {
Once,
Forever,
Count(u32),
}
#[derive(Copy, Clone, Debug)]
pub struct Ramp<C = MonotonicCurveLut256> {
pub duration_ms: u32,
pub from: u16,
pub to: u16,
pub curve: C,
pub step: u16,
pub rounding: Rounding,
pub min_dt_ms: u32,
pub lra_frequency_hz: Option<u16>,
pub lra_frequency_hz_to: Option<u16>,
}
impl<C> Ramp<C> {
pub const fn new(duration_ms: u32, from: u16, to: u16, curve: C) -> Self {
Self {
duration_ms: normalize_duration(duration_ms),
from,
to,
curve,
step: 1,
rounding: Rounding::Nearest,
min_dt_ms: 0,
lra_frequency_hz: None,
lra_frequency_hz_to: None,
}
}
pub const fn with_quantization(mut self, step: u16, rounding: Rounding) -> Self {
self.step = normalize_step(step);
self.rounding = rounding;
self
}
pub const fn with_min_dt(mut self, min_dt_ms: u32) -> Self {
self.min_dt_ms = min_dt_ms;
self
}
pub const fn with_lra_frequency(mut self, frequency_hz: u16) -> Self {
self.lra_frequency_hz = Some(frequency_hz);
self
}
}
#[derive(Copy, Clone, Debug)]
pub enum Instruction<C = MonotonicCurveLut256> {
Ramp(Ramp<C>),
Hold {
duration_ms: u32,
level: u16,
lra_frequency_hz: Option<u16>,
},
Pause {
duration_ms: u32,
},
}
impl<C> Instruction<C> {
pub const fn ramp(duration_ms: u32, from: u16, to: u16, curve: C) -> Self {
Self::Ramp(Ramp::new(duration_ms, from, to, curve))
}
pub const fn hold(duration_ms: u32, level: u16) -> Self {
Self::Hold {
duration_ms: normalize_duration(duration_ms),
level,
lra_frequency_hz: None,
}
}
pub const fn hold_with_lra_frequency(duration_ms: u32, level: u16, frequency_hz: u16) -> Self {
Self::Hold {
duration_ms: normalize_duration(duration_ms),
level,
lra_frequency_hz: Some(frequency_hz),
}
}
pub const fn pause(duration_ms: u32) -> Self {
Self::Pause {
duration_ms: normalize_duration(duration_ms),
}
}
pub const fn duration_ms(&self) -> u32 {
match self {
Self::Ramp(ramp) => ramp.duration_ms,
Self::Hold { duration_ms, .. } | Self::Pause { duration_ms } => *duration_ms,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct Program<'a, C = MonotonicCurveLut256> {
motor: MotorKind,
instructions: &'a [Instruction<C>],
loop_mode: LoopMode,
}
impl<'a, C> Program<'a, C> {
pub const fn new(motor: MotorKind, instructions: &'a [Instruction<C>]) -> Self {
Self {
motor,
instructions,
loop_mode: LoopMode::Once,
}
}
pub const fn with_loop_mode(mut self, loop_mode: LoopMode) -> Self {
self.loop_mode = loop_mode;
self
}
pub const fn repeat_forever(self) -> Self {
self.with_loop_mode(LoopMode::Forever)
}
pub const fn motor(&self) -> MotorKind {
self.motor
}
pub const fn loop_mode(&self) -> LoopMode {
self.loop_mode
}
pub const fn instructions(&self) -> &'a [Instruction<C>] {
self.instructions
}
pub const fn is_empty(&self) -> bool {
self.instructions.is_empty()
}
pub fn total_duration_ms(&self) -> u32 {
let mut total = 0u32;
let mut index = 0usize;
while index < self.instructions.len() {
total = total.saturating_add(self.instructions[index].duration_ms());
index += 1;
}
total
}
}
pub(crate) const fn normalize_step(step: u16) -> u16 {
if step == 0 { 1 } else { step }
}
const fn normalize_duration(duration_ms: u32) -> u32 {
if duration_ms == 0 { 1 } else { duration_ms }
}