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}