ic_md/
configs.rs

1//! Module to hold the configuration and status structs for the device
2
3use core::{convert::From, default::Default, fmt::Debug};
4
5/// Represent the counter values for different configurations of the iC-MD quadrature counter.
6///
7/// If more than one counter value is present, the counter values are always in the order of
8/// Counter 0, Counter 1, and Counter 2.
9/// Note: The size of the returned value depends on the configuration of the counter!
10#[derive(Debug)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub enum CntCount {
13    /// Counter return value for configuration counter 0 = 24 bit; 1 counter; TTL, RS422, or LVDS
14    Cnt1Bit24(i32),
15    /// Counter return value for configuration counter 0 = 24 bit and Counter 1 = 24 bit; 2 counters; TTL only
16    Cnt2Bit24(i32, i32),
17    /// Counter return value for configuration counter 0 = 48 bit; 1 counter; TTL, RS422, or LVDS
18    Cnt1Bit48(i64),
19    /// Counter return value for configuration counter 0 = 16 bit; 1 counter; TTL, RS422, or LVDS
20    Cnt1Bit16(i16),
21    /// Counter return value for configuration counter 0 = 32 bit; 1 counter; TTL, RS422, or LVDS
22    Cnt1Bit32(i32),
23    /// Counter return value for configuration counter 0 = 32 bit and Counter 1 = 16 bit; 2 counters; TTL only
24    Cnt2Bit32Bit16(i16, i32),
25    /// Counter return value for configuration counter 0 = 16 bit and Counter 1 = 16 bit; 2 counters; TTL only
26    Cnt2Bit16(i16, i16),
27    /// Counter return value for configuration counter 0 = 16 bit, Counter 1 = 16 bit, and Counter 2 = 16 bit;
28    /// 3 counters; TTL only
29    Cnt3Bit16(i16, i16, i16),
30}
31
32impl CntCount {
33    /// Get the value of the counter zero
34    ///
35    /// If it exists, this will return `Some(value)`. Otherwise it will return `None`. For counter
36    /// zero, this will always exist, as it is always configured.
37    pub fn get_cnt0(&self) -> Option<i64> {
38        match self {
39            CntCount::Cnt1Bit24(val) => Some(*val as i64),
40            CntCount::Cnt2Bit24(val, _) => Some(*val as i64),
41            CntCount::Cnt1Bit48(val) => Some(*val),
42            CntCount::Cnt1Bit16(val) => Some(*val as i64),
43            CntCount::Cnt1Bit32(val) => Some(*val as i64),
44            CntCount::Cnt2Bit32Bit16(val, _) => Some(*val as i64),
45            CntCount::Cnt2Bit16(val, _) => Some(*val as i64),
46            CntCount::Cnt3Bit16(val, _, _) => Some(*val as i64),
47        }
48    }
49
50    /// Get the value of the counter one
51    ///
52    /// If it exists, this will return `Some(value)`. Otherwise it will return `None`.
53    pub fn get_cnt1(&self) -> Option<i64> {
54        match self {
55            CntCount::Cnt2Bit24(_, val) => Some(*val as i64),
56            CntCount::Cnt2Bit32Bit16(_, val) => Some(*val as i64),
57            CntCount::Cnt2Bit16(_, val) => Some(*val as i64),
58            CntCount::Cnt3Bit16(_, val, _) => Some(*val as i64),
59            _ => None,
60        }
61    }
62
63    /// Get the value of counter two.
64    ///
65    /// If it exists, this will return `Some(value)`. Otherwise it will return `None`.
66    pub fn get_cnt2(&self) -> Option<i64> {
67        match self {
68            CntCount::Cnt3Bit16(_, _, val) => Some(*val as i64),
69            _ => None,
70        }
71    }
72}
73
74/// Enum to specify the direction in which a counter counts
75///
76/// This enum is used to turn the positive direction of counting around. By default, it is set to
77/// CW for positive counting, but can be set to CCW for positive counting.
78#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum CntDirection {
81    /// Clockwise counting direction
82    #[default]
83    CW,
84    /// Counterclockwise counting direction
85    CCW,
86}
87
88impl From<CntDirection> for u8 {
89    fn from(val: CntDirection) -> Self {
90        match val {
91            CntDirection::CW => 0,
92            CntDirection::CCW => 1,
93        }
94    }
95}
96
97/// Enum to specify if the Z signal is normal or inverted
98#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
99#[cfg_attr(feature = "defmt", derive(defmt::Format))]
100pub enum CntZSignal {
101    #[default]
102    /// Normal Z signal
103    Normal,
104    /// Inverted Z signal
105    Inverted,
106}
107
108impl From<CntZSignal> for u8 {
109    fn from(val: CntZSignal) -> Self {
110        match val {
111            CntZSignal::Normal => 0,
112            CntZSignal::Inverted => 1,
113        }
114    }
115}
116
117/// Setup for a specific counter.
118///
119/// Use this struct to declare the setup of a specific counter.
120#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
121#[cfg_attr(feature = "defmt", derive(defmt::Format))]
122pub struct CntSetup {
123    count_direction: CntDirection,
124    z_signal: CntZSignal,
125}
126
127impl CntSetup {
128    /// Create a new counter setup with the given direction and Z signal.
129    pub fn new(count_direction: CntDirection, z_signal: CntZSignal) -> Self {
130        Self {
131            count_direction,
132            z_signal,
133        }
134    }
135}
136
137/// Counter configuration
138///
139/// The iC-MD can be configured for 1 up to 3 channels with counter lengths of 16 to 48
140/// bits. Each counter can furthermore be specified to count in clockwise or counterclockwise
141/// direction. Finally, you can also configure if the Z signal is normal or inverted.
142/// For the setup with three counters, the Z signal setup will simply be ignored as there are no
143/// connections for Z signals available. See datasheet for more information.
144///
145/// If you enable the `defmt` feature, this enum will contain a `defmt::Format`
146/// implementation for logging the current configuration.
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148#[cfg_attr(feature = "defmt", derive(defmt::Format))]
149pub enum CntCfg {
150    /// Counter 0 = 24 bit; 1 counter; TTL, RS422, or LVDS
151    Cnt1Bit24(CntSetup),
152    /// Counter 0 = 24 bit and Counter 1 = 24 bit; 2 counters; TTL only
153    Cnt2Bit24(CntSetup, CntSetup),
154    /// Counter 0 = 48 bit; 1 counter; TTL, RS422, or LVDS
155    Cnt1Bit48(CntSetup),
156    /// Counter 0 = 16 bit; 1 counter; TTL, RS422, or LVDS
157    Cnt1Bit16(CntSetup),
158    /// Counter 0 = 32 bit; 1 counter; TTL, RS422, or LVDS
159    Cnt1Bit32(CntSetup),
160    /// Counter 0 = 32 bit and Counter 1 = 16 bit; 2 counters; TTL only
161    Cnt2Bit32Bit16(CntSetup, CntSetup),
162    /// Counter 0 = 16 bit and Counter 1 = 16 bit; 2 counters; TTL only
163    Cnt2Bit16(CntSetup, CntSetup),
164    /// Counter 0 = 16 bit, Counter 1 = 16 bit, and Counter 2 = 16 bit; 3 counters; TTL
165    /// only
166    Cnt3Bit16(CntSetup, CntSetup, CntSetup),
167}
168
169impl From<CntCfg> for u8 {
170    fn from(val: CntCfg) -> Self {
171        match val {
172            CntCfg::Cnt1Bit24(i) => {
173                // Config is 0b000
174                (u8::from(i.count_direction) << 3) | (u8::from(i.z_signal) << 6)
175            }
176            CntCfg::Cnt2Bit24(i, j) => {
177                // Config is 0b001
178                0b001
179                    | (u8::from(i.count_direction) << 3)
180                    | (u8::from(i.z_signal) << 6)
181                    | (u8::from(j.count_direction) << 4)
182                    | (u8::from(j.z_signal) << 7)
183            }
184            CntCfg::Cnt1Bit48(i) => {
185                // Config is 0b010
186                0b010 | (u8::from(i.count_direction) << 3) | (u8::from(i.z_signal) << 6)
187            }
188            CntCfg::Cnt1Bit16(i) => {
189                // Config is 0b011
190                0b011 | (u8::from(i.count_direction) << 3) | (u8::from(i.z_signal) << 6)
191            }
192            CntCfg::Cnt1Bit32(i) => {
193                // Config is 0b100
194                0b100 | (u8::from(i.count_direction) << 3) | (u8::from(i.z_signal) << 6)
195            }
196            CntCfg::Cnt2Bit32Bit16(i, j) => {
197                // Config is 0b101
198                0b101
199                    | (u8::from(i.count_direction) << 3)
200                    | (u8::from(i.z_signal) << 6)
201                    | (u8::from(j.count_direction) << 4)
202                    | (u8::from(j.z_signal) << 7)
203            }
204            CntCfg::Cnt2Bit16(i, j) => {
205                // Config is 0b110
206                0b110
207                    | (u8::from(i.count_direction) << 3)
208                    | (u8::from(i.z_signal) << 6)
209                    | (u8::from(j.count_direction) << 4)
210                    | (u8::from(j.z_signal) << 7)
211            }
212            CntCfg::Cnt3Bit16(i, j, k) => {
213                // Config is 0b111, z signals are ignored as they cannot be connected!
214                0b111
215                    | (u8::from(i.count_direction) << 3)
216                    | (u8::from(j.count_direction) << 4)
217                    | (u8::from(k.count_direction) << 5)
218            }
219        }
220    }
221}
222
223/// Device Status
224///
225/// This struct describes the status of the device. The variables that indicate if a warning or
226/// error has occured. This status is updated whenever the counters are read, as errors and
227/// warnings are sent along.
228///
229/// Note: You are responsible for reading these warnings. Alternatively, you can also query the
230/// connected pins `NWARN` and `NERR`.
231#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
232#[cfg_attr(feature = "defmt", derive(defmt::Format))]
233pub struct DeviceStatus {
234    pub(crate) warning: WarningStatus,
235    pub(crate) error: ErrorStatus,
236}
237
238impl DeviceStatus {
239    /// Return `true` if the device has no errors or warnings, false otherwise.
240    pub fn is_ok(&self) -> bool {
241        self.warning == WarningStatus::Ok && self.error == ErrorStatus::Ok
242    }
243
244    /// Get the current warning status.
245    pub fn get_warning(&self) -> WarningStatus {
246        self.warning
247    }
248
249    /// Get the current error status.
250    pub fn get_error(&self) -> ErrorStatus {
251        self.error
252    }
253}
254
255/// Full Device Status
256///
257/// This struct contains the full status of the device that is returned when reading the status
258/// registers. For most registers, reading the status will reset the status bits to `Ok` or the
259/// equivalent for the specific status.
260///
261/// Note: Even if you have only one counter configured, the full device status will still be
262/// reported, i.t., other counters (which don't exist in your setup) will also be reported.
263#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
264#[cfg_attr(feature = "defmt", derive(defmt::Format))]
265pub struct FullDeviceStatus {
266    /// Overflow of counter 0
267    pub cnt0_overflow: OverflowStatus,
268    /// Decodification error of AB inputs in counter 0
269    pub cnt0_aberr: DecodificationStatus,
270    /// Zero status of counter 0
271    pub cnt0_zero: ZeroStatus,
272    /// Overflow of counter 1
273    pub cnt1_overflow: OverflowStatus,
274    /// Decodification error of AB inputs in counter 1
275    pub cnt1_aberr: DecodificationStatus,
276    /// Zero status of counter 1
277    pub cnt1_zero: ZeroStatus,
278    /// Overflow of counter 2
279    pub cnt2_overflow: OverflowStatus,
280    /// Decodification error of AB inputs in counter 2
281    pub cnt2_aberr: DecodificationStatus,
282    /// Zero status of counter 2
283    pub cnt2_zero: ZeroStatus,
284    /// Power status: Has an undervoltage reset occured?
285    pub power_status: UndervoltageStatus,
286    /// Reference register status: Is the reference register valid?
287    pub ref_reg_status: RegisterStatus,
288    /// UPD register status: Is the UPD register valid?
289    pub upd_reg_status: RegisterStatus,
290    /// Reference counter status.
291    pub ref_cnt_status: OverflowStatus,
292    /// External error status: Has an external error occured?
293    pub ext_err_status: ErrorStatus,
294    /// External warning status: Has an external warning occured?
295    pub ext_warn_status: WarningStatus,
296    /// Communication status: Has a communication collision occured?
297    pub comm_status: CommunicationStatus,
298    /// Touch probe status: Are the TPx registers updated?
299    pub tp_status: TouchProbeStatus,
300    /// TPI pin status
301    pub tpi_status: PinStatus,
302    /// SSI enabled status: Is the SSI interface enabled?
303    pub ssi_enabled: InterfaceStatus,
304}
305
306/// Actuator status.
307///
308/// This struct is used to keep track of the status of the actuator pins. Upon first initialization
309/// they are both set to `PinStatus::Low`. The actuator pins are ACT0 and ACT1.
310#[derive(Debug, Default, PartialEq, Eq)]
311#[cfg_attr(feature = "defmt", derive(defmt::Format))]
312pub struct ActuatorStatus {
313    /// Status of the ACT0 pin
314    pub act0: PinStatus,
315    /// Status of the ACT1 pin
316    pub act1: PinStatus,
317}
318
319/// Warning Status
320///
321/// Enum that indicates if a warning has occured or not.
322#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
323#[cfg_attr(feature = "defmt", derive(defmt::Format))]
324pub enum WarningStatus {
325    #[default]
326    /// No warning has occured.
327    Ok,
328    /// A warning has occured.
329    Warning,
330}
331
332impl From<bool> for WarningStatus {
333    fn from(val: bool) -> Self {
334        match val {
335            false => WarningStatus::Ok, // For a real warning, not an NWarn!
336            true => WarningStatus::Warning,
337        }
338    }
339}
340
341/// Error Status
342///
343/// Enum that indicates if an error has occured or not.
344#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
345#[cfg_attr(feature = "defmt", derive(defmt::Format))]
346pub enum ErrorStatus {
347    #[default]
348    /// No error has occured.
349    Ok,
350    /// An error has occured.
351    Error,
352}
353
354impl From<bool> for ErrorStatus {
355    fn from(val: bool) -> Self {
356        match val {
357            false => ErrorStatus::Ok, // For a real error, not an NErr!
358            true => ErrorStatus::Error,
359        }
360    }
361}
362
363/// Decodification Status
364///
365/// A DecodificationError indicates that either the counting frequency is too high or that
366/// two incremental edges are too close together.
367#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
368#[cfg_attr(feature = "defmt", derive(defmt::Format))]
369pub enum DecodificationStatus {
370    #[default]
371    /// No decodification error has occured.
372    Ok,
373    /// A decodification error has occured.
374    DecodificationError,
375}
376
377impl From<bool> for DecodificationStatus {
378    fn from(val: bool) -> Self {
379        match val {
380            false => DecodificationStatus::Ok,
381            true => DecodificationStatus::DecodificationError,
382        }
383    }
384}
385
386/// Overflow Status
387#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
388#[cfg_attr(feature = "defmt", derive(defmt::Format))]
389pub enum OverflowStatus {
390    #[default]
391    /// No overflow has occured.
392    Ok,
393    /// An overflow has occured.
394    Overflow,
395}
396
397impl From<bool> for OverflowStatus {
398    fn from(val: bool) -> Self {
399        match val {
400            false => OverflowStatus::Ok,
401            true => OverflowStatus::Overflow,
402        }
403    }
404}
405
406/// Zero Status
407///
408/// This enum indicates if the counter has reached the zero value or not.
409#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
410#[cfg_attr(feature = "defmt", derive(defmt::Format))]
411pub enum ZeroStatus {
412    #[default]
413    /// The counter is not at zero.
414    NotZero,
415    /// The counter is at zero.
416    Zero,
417}
418
419impl From<bool> for ZeroStatus {
420    fn from(val: bool) -> Self {
421        match val {
422            false => ZeroStatus::NotZero,
423            true => ZeroStatus::Zero,
424        }
425    }
426}
427
428/// Power Status
429///
430/// If VDD falls below the power off supply level, the device is reset and the RAM initialized to
431/// the default value. This status bit indicates that this initialization has taken place (and you
432/// might want to consider re-initializing the device).
433#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435pub enum UndervoltageStatus {
436    #[default]
437    /// The device is running normally and has not been reset due to undervoltage.
438    Ok,
439    /// The device has been reset due to undervoltage.
440    Undervoltage,
441}
442
443impl From<bool> for UndervoltageStatus {
444    fn from(val: bool) -> Self {
445        match val {
446            false => UndervoltageStatus::Ok,
447            true => UndervoltageStatus::Undervoltage,
448        }
449    }
450}
451
452/// Register Status
453///
454/// This enum indicates if a register is valid (Ok) or not (Invalid).
455#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
456#[cfg_attr(feature = "defmt", derive(defmt::Format))]
457pub enum RegisterStatus {
458    #[default]
459    /// The register is valid
460    Ok,
461    /// The register is not valid
462    Invalid,
463}
464
465impl From<bool> for RegisterStatus {
466    fn from(val: bool) -> Self {
467        match val {
468            true => RegisterStatus::Ok,
469            false => RegisterStatus::Invalid,
470        }
471    }
472}
473
474/// Touch probe Status
475///
476/// This enum indicates if the TPx registers are not loaded / have not been updated or if new
477/// values were loaded into the them.
478#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
479#[cfg_attr(feature = "defmt", derive(defmt::Format))]
480pub enum TouchProbeStatus {
481    #[default]
482    /// The TPx registers have not been updated or are not loaded.
483    NotUpdated,
484    /// The TPx registers have been updated and contain new values.
485    Updated,
486}
487
488impl From<bool> for TouchProbeStatus {
489    fn from(val: bool) -> Self {
490        match val {
491            false => TouchProbeStatus::NotUpdated,
492            true => TouchProbeStatus::Updated,
493        }
494    }
495}
496
497/// Communication Status
498///
499/// This enum indicates if the communication with the device has experienced a collision or not.
500#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
501#[cfg_attr(feature = "defmt", derive(defmt::Format))]
502pub enum CommunicationStatus {
503    #[default]
504    /// No collision has occurred, communication is ok.
505    Ok,
506    /// A collision has occurred, communication is not ok.
507    Collision,
508}
509
510impl From<bool> for CommunicationStatus {
511    fn from(val: bool) -> Self {
512        match val {
513            false => CommunicationStatus::Ok,
514            true => CommunicationStatus::Collision,
515        }
516    }
517}
518
519/// Interface Status
520/// This enum indicates if an interface is enabled or disabled.
521#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
522#[cfg_attr(feature = "defmt", derive(defmt::Format))]
523pub enum InterfaceStatus {
524    #[default]
525    /// The interface is disabled.
526    Disabled,
527    /// The interface is enabled.
528    Enabled,
529}
530
531impl From<bool> for InterfaceStatus {
532    fn from(val: bool) -> Self {
533        match val {
534            false => InterfaceStatus::Disabled,
535            true => InterfaceStatus::Enabled,
536        }
537    }
538}
539
540/// Status enum for pins.
541///
542/// `PinStatus::High` means that the pin is at VDD, `PinStatus::Low` means that the pin is at GND.
543#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
544#[cfg_attr(feature = "defmt", derive(defmt::Format))]
545pub enum PinStatus {
546    #[default]
547    /// Pin is at low level (GND)
548    Low,
549    /// Pin is at high level (VDD)
550    High,
551}
552
553impl From<&PinStatus> for bool {
554    fn from(val: &PinStatus) -> Self {
555        match val {
556            PinStatus::High => true,
557            PinStatus::Low => false,
558        }
559    }
560}
561
562impl From<bool> for PinStatus {
563    fn from(val: bool) -> Self {
564        match val {
565            true => PinStatus::High,
566            false => PinStatus::Low,
567        }
568    }
569}