Skip to main content

esp_idf_hal/
units.rs

1//! Units of measurement implementation for times and frequencies.
2//!
3//! It provides type safety, easy conversion and limited arithmetic support.
4//!
5//! # Usage
6//!
7//! ```
8//! let frequency_mhz_1 = MegaHertz(10),
9//! let frequency_mhz_2 = 10.MHz(),
10//! let frequency_khz_1: KiloHertz = frequency_mhz_1.into(),
11//! let frequency_khz_2 = KiloHertz::from(frequency_mhz_2),
12//! let frequency_khz_3 = frequency_khz_1 + 10.MHz().into(),
13//! let frequency_hz_1 = 1.Hz() + frequency_khz_3.into(),
14//! ```
15
16use core::fmt;
17
18pub type ValueType = u32;
19pub type LargeValueType = u64;
20
21pub trait Quantity: Sized {}
22pub trait Time: Quantity + Into<NanoSeconds> {}
23pub trait Frequency: Quantity + Into<Hertz> {}
24pub trait Count: Quantity + Into<Ticks> {}
25
26pub trait TimeU64: Quantity + Into<NanoSecondsU64> {}
27pub trait FrequencyU64: Quantity + Into<HertzU64> {}
28pub trait CountU64: Quantity + Into<TicksU64> {}
29
30/// defines and implements extension traits for quantities with units
31macro_rules! define {
32    ($primitive:ident, $trait:ident, $( ($type: ident, $quantity: ident, $unit: ident,
33        $print_unit: literal), )+) => {
34        $(
35            #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Default)]
36            pub struct $quantity(pub $primitive);
37
38            impl Quantity for $quantity {}
39            impl $type for $quantity {}
40        )*
41
42        pub trait $trait {
43            $(
44                #[allow(non_snake_case)]
45                fn $unit(self) -> $quantity;
46            )*
47        }
48
49        impl $trait for $primitive {
50            $(
51                fn $unit(self) -> $quantity {
52                    $quantity(self)
53                }
54            )*
55        }
56
57        $(
58            impl From<$quantity> for $primitive {
59                fn from(x: $quantity) -> Self {
60                    x.0
61                }
62            }
63
64            impl From<$primitive> for $quantity {
65                fn from(x: $primitive) -> $quantity {
66                    $quantity(x)
67                }
68            }
69
70            impl fmt::Debug for $quantity {
71                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72                    write!(f, "{}{}", self.0, $print_unit)
73                }
74            }
75
76            impl fmt::Display for $quantity {
77                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78                    write!(f, "{}{}", self.0, $print_unit)
79                }
80            }
81
82            impl core::ops::Div<$primitive> for $quantity {
83                type Output = Self;
84                fn div(self, rhs: $primitive) -> Self::Output {
85                    $quantity(self.0/rhs)
86                }
87            }
88
89            impl core::ops::Mul<$primitive> for $quantity {
90                type Output = Self;
91                fn mul(self, rhs: $primitive) -> Self::Output {
92                    $quantity(self.0*rhs)
93                }
94            }
95
96            impl core::ops::Mul<$quantity> for $primitive {
97                type Output = $quantity;
98                fn mul(self, rhs: $quantity) -> Self::Output {
99                    $quantity(self*rhs.0)
100                }
101            }
102
103            impl core::ops::Div<$quantity> for $quantity {
104                type Output = $primitive;
105                fn div(self, rhs: Self) -> Self::Output {
106                    self.0/rhs.0
107                }
108            }
109
110            impl core::ops::Add<$quantity> for $quantity {
111                type Output = Self;
112                fn add(self, rhs: Self) -> Self::Output {
113                    Self(self.0+rhs.0)
114                }
115            }
116
117            impl core::ops::Sub<$quantity> for $quantity {
118                type Output = Self;
119                fn sub(self, rhs: Self) -> Self::Output {
120                    Self(self.0-rhs.0)
121                }
122            }
123        )*
124    };
125}
126
127/// Define ValueType and LargeValueType quantities and conversion from ValueType to LargeValueType
128macro_rules! define_large {
129    ($( ($type: ident, $quantity: ident, $unit:ident, $type_large: ident,
130            $quantity_large: ident, $unit_large:ident, $print_unit: literal) ),+) => {
131
132        define!(
133            ValueType,
134            FromValueType,
135            $(($type, $quantity, $unit, $print_unit),)*
136        );
137
138        define!(
139            LargeValueType,
140            FromLargeValueType,
141            $(($type_large, $quantity_large, $unit_large, $print_unit),)*
142        );
143
144        $(
145        impl From<$quantity> for $quantity_large {
146            fn from(x: $quantity) -> Self {
147                Self(LargeValueType::from(x.0))
148            }
149        }
150        impl TryFrom<$quantity_large> for $quantity {
151            type Error=core::num::TryFromIntError;
152            fn try_from(x: $quantity_large) -> Result<$quantity, Self::Error> {
153                Ok(Self(ValueType::try_from(x.0)?))
154            }
155        }
156        )*
157
158    };
159}
160
161/// defines From trait for pair or quantities with scaling
162macro_rules! convert {
163    ($( ($from: ty, $from_large: ty, $into: ty, $into_large: ty, $factor: expr) ),+) => {
164        $(
165        impl From<$from> for $into {
166            fn from(x: $from) -> Self {
167                Self(x.0 * $factor)
168            }
169        }
170        impl From<$from> for $into_large {
171            fn from(x: $from) -> Self {
172                Self(LargeValueType::from(x.0) * $factor)
173            }
174        }
175        impl From<$from_large> for $into_large {
176            fn from(x: $from_large) -> Self {
177                Self(x.0 * $factor)
178            }
179        }
180        )*
181    };
182}
183
184/// defines multiply trait for frequency and time
185macro_rules! multiply {
186    ($( ($time: ty, $time_large: ty, $freq: ty, $freq_large: ty,
187        $factor: expr, $divider: expr) ),+) => {
188        $(
189        impl core::ops::Mul<$freq> for $time {
190            type Output = Ticks;
191            fn mul(self, rhs: $freq) -> Self::Output {
192                TicksU64::from(LargeValueType::from(self.0) * LargeValueType::from(rhs.0)
193                    * $factor / $divider).try_into().unwrap()
194            }
195        }
196
197        impl core::ops::Mul<$time> for $freq {
198            type Output = Ticks;
199            fn mul(self, rhs: $time) -> Self::Output {
200                TicksU64::from(LargeValueType::from(self.0) * LargeValueType::from(rhs.0)
201                    * $factor / $divider).try_into().unwrap()
202            }
203        }
204
205        impl core::ops::Mul<$freq_large> for $time_large {
206            type Output = TicksU64;
207            fn mul(self, rhs: $freq_large) -> Self::Output {
208                (self.0 * rhs.0 * $factor / $divider).into()
209            }
210        }
211
212        impl core::ops::Mul<$time_large> for $freq_large {
213            type Output = TicksU64;
214            fn mul(self, rhs: $time_large) -> Self::Output {
215                (self.0 * rhs.0 * $factor / $divider).into()
216            }
217        }
218
219        impl core::ops::Mul<$freq> for $time_large {
220            type Output = TicksU64;
221            fn mul(self, rhs: $freq) -> Self::Output {
222                (self.0 * LargeValueType::from(rhs.0) * $factor / $divider).into()
223            }
224        }
225
226        impl core::ops::Mul<$time> for $freq_large {
227            type Output = TicksU64;
228            fn mul(self, rhs: $time) -> Self::Output {
229                (self.0 * LargeValueType::from(rhs.0) * $factor / $divider).into()
230            }
231        }
232
233        impl core::ops::Mul<$freq_large> for $time {
234            type Output = TicksU64;
235            fn mul(self, rhs: $freq_large) -> Self::Output {
236                (LargeValueType::from(self.0) * rhs.0 * $factor / $divider).into()
237            }
238        }
239
240        impl core::ops::Mul<$time_large> for $freq {
241            type Output = TicksU64;
242            fn mul(self, rhs: $time_large) -> Self::Output {
243                (LargeValueType::from(self.0) * rhs.0 * $factor / $divider).into()
244            }
245        }
246        )*
247    };
248}
249
250macro_rules! divide {
251    ($( ($freq: ty, $freq_large: ty, $time: ty, $time_large: ty, $factor: expr) ),+) => {
252        $(
253        impl core::ops::Div<$freq> for Ticks {
254            type Output = $time;
255            fn div(self, rhs: $freq) -> Self::Output {
256                ValueType::try_from(
257                    LargeValueType::from(self.0) * $factor / LargeValueType::from(rhs.0)
258                ).unwrap().into()
259            }
260        }
261
262        impl core::ops::Div<$freq> for TicksU64 {
263            type Output = $time_large;
264            fn div(self, rhs: $freq) -> Self::Output {
265                (self.0 * $factor / LargeValueType::from(rhs.0)).into()
266            }
267        }
268
269        impl core::ops::Div<$freq_large> for TicksU64 {
270            type Output = $time_large;
271            fn div(self, rhs: $freq_large) -> Self::Output {
272                (self.0 * $factor / rhs.0).into()
273            }
274        }
275
276        impl core::ops::Div<$freq_large> for Ticks {
277            type Output = $time_large;
278            fn div(self, rhs: $freq_large) -> Self::Output {
279                (LargeValueType::from(self.0) * $factor / rhs.0).into()
280            }
281        }
282        )*
283    };
284}
285
286#[rustfmt::skip::macros(define_large)]
287define_large!(
288    (Frequency, Hertz,        Hz,    FrequencyU64, HertzU64,        Hz_large,    "Hz"  ),
289    (Frequency, KiloHertz,    kHz,   FrequencyU64, KiloHertzU64,    kHz_large,   "kHz" ),
290    (Frequency, MegaHertz,    MHz,   FrequencyU64, MegaHertzU64,    MHz_large,   "MHz" ),
291    (Time,      NanoSeconds,  ns,    TimeU64,      NanoSecondsU64,  ns_large,    "ns"  ),
292    (Time,      MicroSeconds, us,    TimeU64,      MicroSecondsU64, us_large,    "us"  ),
293    (Time,      MilliSeconds, ms,    TimeU64,      MilliSecondsU64, ms_large,    "ms"  ),
294    (Time,      Seconds,      s,     TimeU64,      SecondsU64,      s_large,     "s"   ),
295    (Count,     Ticks,        ticks, CountU64,     TicksU64,        ticks_large, ""    )
296);
297
298#[rustfmt::skip::macros(convert)]
299convert!(
300    (KiloHertz,    KiloHertzU64,    Hertz,        HertzU64,        1_000         ),
301    (MegaHertz,    MegaHertzU64,    Hertz,        HertzU64,        1_000_000     ),
302    (MegaHertz,    MegaHertzU64,    KiloHertz,    KiloHertzU64,    1_000         ),
303    (Seconds,      SecondsU64,      MilliSeconds, MilliSecondsU64, 1_000         ),
304    (Seconds,      SecondsU64,      MicroSeconds, MicroSecondsU64, 1_000_000     ),
305    (Seconds,      SecondsU64,      NanoSeconds,  NanoSecondsU64,  1_000_000_000 ),
306    (MilliSeconds, MilliSecondsU64, MicroSeconds, MicroSecondsU64, 1_000         ),
307    (MilliSeconds, MilliSecondsU64, NanoSeconds,  NanoSecondsU64,  1_000_000     ),
308    (MicroSeconds, MicroSecondsU64, NanoSeconds,  NanoSecondsU64,  1_000         )
309);
310
311#[rustfmt::skip::macros(multiply)]
312multiply!(
313    (Seconds,      SecondsU64,      Hertz,     HertzU64,     1,         1             ),
314    (Seconds,      SecondsU64,      KiloHertz, KiloHertzU64, 1_000,     1             ),
315    (Seconds,      SecondsU64,      MegaHertz, MegaHertzU64, 1_000_000, 1             ),
316    (MilliSeconds, MilliSecondsU64, Hertz,     HertzU64,     1,         1_000         ),
317    (MilliSeconds, MilliSecondsU64, KiloHertz, KiloHertzU64, 1,         1             ),
318    (MilliSeconds, MilliSecondsU64, MegaHertz, MegaHertzU64, 1_000,     1             ),
319    (MicroSeconds, MicroSecondsU64, Hertz,     HertzU64,     1,         1_000_000     ),
320    (MicroSeconds, MicroSecondsU64, KiloHertz, KiloHertzU64, 1,         1_000         ),
321    (MicroSeconds, MicroSecondsU64, MegaHertz, MegaHertzU64, 1,         1             ),
322    (NanoSeconds,  NanoSecondsU64,  Hertz,     HertzU64,     1,         1_000_000_000 ),
323    (NanoSeconds,  NanoSecondsU64,  KiloHertz, KiloHertzU64, 1,         1_000_000     ),
324    (NanoSeconds,  NanoSecondsU64,  MegaHertz, MegaHertzU64, 1,         1_000         )
325);
326
327#[rustfmt::skip::macros(divide)]
328divide!(
329    (Hertz,     HertzU64,     NanoSeconds, NanoSecondsU64, 1_000_000_000 ),
330    (KiloHertz, KiloHertzU64, NanoSeconds, NanoSecondsU64, 1_000_000     ),
331    (MegaHertz, MegaHertzU64, NanoSeconds, NanoSecondsU64, 1_000         )
332);