use crate::core::scalar::ControlScalar;
#[derive(Debug, Clone, Copy)]
pub struct FullStepDriver<S: ControlScalar> {
steps_per_rev: u32,
step_count: i64,
step_angle: S,
}
pub type PhasePattern = [bool; 4];
const FULL_STEP_SEQ: [PhasePattern; 4] = [
[true, false, true, false], [false, true, true, false], [false, true, false, true], [true, false, false, true], ];
const WAVE_DRIVE_SEQ: [PhasePattern; 4] = [
[true, false, false, false], [false, false, true, false], [false, true, false, false], [false, false, false, true], ];
impl<S: ControlScalar> FullStepDriver<S> {
pub fn new(steps_per_rev: u32) -> Self {
let step_angle = S::TWO * S::PI / S::from_f64(steps_per_rev as f64);
Self {
steps_per_rev,
step_count: 0,
step_angle,
}
}
pub fn step(&mut self, steps: i32) {
self.step_count += i64::from(steps);
}
pub fn phase_pattern(&self) -> PhasePattern {
let idx = self.step_count.rem_euclid(4) as usize;
FULL_STEP_SEQ[idx]
}
pub fn wave_drive_pattern(&self) -> PhasePattern {
let idx = self.step_count.rem_euclid(4) as usize;
WAVE_DRIVE_SEQ[idx]
}
pub fn position_steps(&self) -> i64 {
self.step_count
}
pub fn position_rad(&self) -> S {
S::from_f64(self.step_count as f64) * self.step_angle
}
pub fn position_deg(&self) -> S {
self.position_rad() * S::from_f64(180.0 / core::f64::consts::PI)
}
pub fn reset(&mut self) {
self.step_count = 0;
}
pub fn steps_per_rev(&self) -> u32 {
self.steps_per_rev
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn initial_pattern() {
let d = FullStepDriver::<f64>::new(200);
let p = d.phase_pattern();
assert_eq!(p, FULL_STEP_SEQ[0]);
}
#[test]
fn step_advances_pattern() {
let mut d = FullStepDriver::<f64>::new(200);
d.step(1);
assert_eq!(d.phase_pattern(), FULL_STEP_SEQ[1]);
d.step(1);
assert_eq!(d.phase_pattern(), FULL_STEP_SEQ[2]);
}
#[test]
fn pattern_wraps_after_4_steps() {
let mut d = FullStepDriver::<f64>::new(200);
d.step(4);
assert_eq!(d.phase_pattern(), FULL_STEP_SEQ[0]);
}
#[test]
fn reverse_direction() {
let mut d = FullStepDriver::<f64>::new(200);
d.step(-1);
assert_eq!(d.phase_pattern(), FULL_STEP_SEQ[3]);
}
#[test]
fn position_tracking() {
let mut d = FullStepDriver::<f64>::new(200);
d.step(100);
assert_eq!(d.position_steps(), 100);
let expected_deg = 100.0 * 360.0 / 200.0;
assert!((d.position_deg() - expected_deg).abs() < 1e-6);
}
#[test]
fn reset_zeroes_position() {
let mut d = FullStepDriver::<f64>::new(200);
d.step(50);
d.reset();
assert_eq!(d.position_steps(), 0);
}
}