stepper_motion/config/
units.rs1use core::ops::{Add, Mul, Sub};
7
8use serde::Deserialize;
9
10use crate::error::ConfigError;
11
12#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default, Deserialize)]
16#[serde(transparent)]
17pub struct Degrees(pub f32);
18
19impl Degrees {
20 #[inline]
22 pub const fn new(value: f32) -> Self {
23 Self(value)
24 }
25
26 #[inline]
28 pub const fn value(self) -> f32 {
29 self.0
30 }
31
32 #[inline]
34 pub fn to_radians(self) -> f32 {
35 self.0.to_radians()
36 }
37
38 #[inline]
40 pub fn from_radians(radians: f32) -> Self {
41 Self(radians.to_degrees())
42 }
43}
44
45impl Add for Degrees {
46 type Output = Self;
47
48 fn add(self, rhs: Self) -> Self::Output {
49 Self(self.0 + rhs.0)
50 }
51}
52
53impl Sub for Degrees {
54 type Output = Self;
55
56 fn sub(self, rhs: Self) -> Self::Output {
57 Self(self.0 - rhs.0)
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default, Deserialize)]
63#[serde(transparent)]
64pub struct DegreesPerSec(pub f32);
65
66impl DegreesPerSec {
67 #[inline]
69 pub const fn new(value: f32) -> Self {
70 Self(value)
71 }
72
73 #[inline]
75 pub const fn value(self) -> f32 {
76 self.0
77 }
78}
79
80impl Mul<f32> for DegreesPerSec {
81 type Output = Self;
82
83 fn mul(self, rhs: f32) -> Self::Output {
84 Self(self.0 * rhs)
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default, Deserialize)]
90#[serde(transparent)]
91pub struct DegreesPerSecSquared(pub f32);
92
93impl DegreesPerSecSquared {
94 #[inline]
96 pub const fn new(value: f32) -> Self {
97 Self(value)
98 }
99
100 #[inline]
102 pub const fn value(self) -> f32 {
103 self.0
104 }
105}
106
107impl Mul<f32> for DegreesPerSecSquared {
108 type Output = Self;
109
110 fn mul(self, rhs: f32) -> Self::Output {
111 Self(self.0 * rhs)
112 }
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
119pub struct Steps(pub i64);
120
121impl Steps {
122 #[inline]
124 pub const fn new(value: i64) -> Self {
125 Self(value)
126 }
127
128 #[inline]
130 pub const fn value(self) -> i64 {
131 self.0
132 }
133
134 #[inline]
136 pub fn abs(self) -> u64 {
137 self.0.unsigned_abs()
138 }
139
140 #[inline]
142 pub fn to_degrees(self, steps_per_degree: f32) -> Degrees {
143 Degrees(self.0 as f32 / steps_per_degree)
144 }
145
146 #[inline]
148 pub fn from_degrees(degrees: Degrees, steps_per_degree: f32) -> Self {
149 Self((degrees.0 * steps_per_degree) as i64)
150 }
151}
152
153impl Add for Steps {
154 type Output = Self;
155
156 fn add(self, rhs: Self) -> Self::Output {
157 Self(self.0 + rhs.0)
158 }
159}
160
161impl Sub for Steps {
162 type Output = Self;
163
164 fn sub(self, rhs: Self) -> Self::Output {
165 Self(self.0 - rhs.0)
166 }
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub struct Microsteps(u16);
174
175impl Microsteps {
176 pub const FULL: Self = Self(1);
178 pub const HALF: Self = Self(2);
180 pub const QUARTER: Self = Self(4);
182 pub const EIGHTH: Self = Self(8);
184 pub const SIXTEENTH: Self = Self(16);
186 pub const THIRTY_SECOND: Self = Self(32);
188 pub const SIXTY_FOURTH: Self = Self(64);
190 pub const ONE_TWENTY_EIGHTH: Self = Self(128);
192 pub const TWO_FIFTY_SIXTH: Self = Self(256);
194
195 const VALID_VALUES: [u16; 9] = [1, 2, 4, 8, 16, 32, 64, 128, 256];
197
198 pub fn new(value: u16) -> Result<Self, ConfigError> {
204 if Self::VALID_VALUES.contains(&value) {
205 Ok(Self(value))
206 } else {
207 Err(ConfigError::InvalidMicrosteps(value))
208 }
209 }
210
211 #[inline]
213 pub const fn value(self) -> u16 {
214 self.0
215 }
216
217 #[inline]
219 pub fn is_valid(value: u16) -> bool {
220 Self::VALID_VALUES.contains(&value)
221 }
222}
223
224impl Default for Microsteps {
225 fn default() -> Self {
226 Self::FULL
227 }
228}
229
230impl TryFrom<u16> for Microsteps {
231 type Error = ConfigError;
232
233 fn try_from(value: u16) -> Result<Self, Self::Error> {
234 Self::new(value)
235 }
236}
237
238impl<'de> Deserialize<'de> for Microsteps {
239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240 where
241 D: serde::Deserializer<'de>,
242 {
243 use core::fmt::Write;
244 let value = u16::deserialize(deserializer)?;
245 Microsteps::new(value).map_err(|e| {
246 let mut buf = heapless::String::<128>::new();
247 let _ = write!(buf, "{}", e);
248 serde::de::Error::custom(buf.as_str())
249 })
250 }
251}
252
253pub trait UnitExt {
255 fn degrees(self) -> Degrees;
257 fn degrees_per_sec(self) -> DegreesPerSec;
259 fn degrees_per_sec_squared(self) -> DegreesPerSecSquared;
261}
262
263impl UnitExt for f32 {
264 #[inline]
265 fn degrees(self) -> Degrees {
266 Degrees(self)
267 }
268
269 #[inline]
270 fn degrees_per_sec(self) -> DegreesPerSec {
271 DegreesPerSec(self)
272 }
273
274 #[inline]
275 fn degrees_per_sec_squared(self) -> DegreesPerSecSquared {
276 DegreesPerSecSquared(self)
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283
284 #[test]
285 fn test_microsteps_valid_values() {
286 for &v in &Microsteps::VALID_VALUES {
287 assert!(Microsteps::new(v).is_ok());
288 }
289 }
290
291 #[test]
292 fn test_microsteps_invalid_values() {
293 assert!(Microsteps::new(0).is_err());
294 assert!(Microsteps::new(3).is_err());
295 assert!(Microsteps::new(17).is_err());
296 assert!(Microsteps::new(512).is_err());
297 }
298
299 #[test]
300 fn test_degrees_conversion() {
301 let d = Degrees::new(180.0);
302 assert!((d.to_radians() - core::f32::consts::PI).abs() < 0.0001);
303 }
304
305 #[test]
306 fn test_steps_to_degrees() {
307 let steps = Steps::new(3200);
308 let steps_per_degree = 3200.0 / 360.0;
309 let degrees = steps.to_degrees(steps_per_degree);
310 assert!((degrees.value() - 360.0).abs() < 0.01);
311 }
312}