autd3_driver/firmware/fpga/
gpio_out.rs

1use crate::{ethercat::DcSysTime, geometry::Transducer};
2
3use derive_more::Debug;
4use zerocopy::{Immutable, IntoBytes};
5
6use super::ec_time_to_sys_time;
7
8/// Output of the GPIO pin. See also [`GPIOOutputs`].
9///
10/// [`GPIOOutputs`]: crate::datagram::GPIOOutputs
11#[non_exhaustive]
12#[derive(Clone, Debug)]
13pub enum GPIOOutputType<'a> {
14    /// Do not output.
15    None,
16    /// Base signal (50% duty cycle square wave with the same frequency as ultrasound).
17    BaseSignal,
18    /// High if the temperature sensor is asserted.
19    Thermo,
20    /// High if the ForceFan flag is asserted.
21    ForceFan,
22    /// EtherCAT synchronization signal.
23    Sync,
24    /// Modulation segment (High if the segment is 1, Low if the segment is 0).
25    ModSegment,
26    #[debug("ModIdx({})", _0)]
27    /// High when the Modulation index is the specified value.
28    ModIdx(u16),
29    /// STM and Gain segment (High if the segment is 1, Low if the segment is 0).
30    StmSegment,
31    #[debug("StmIdx({})", _0)]
32    /// High when the STM index is the specified value.
33    StmIdx(u16),
34    /// High if FociSTM/GainSTM is used.
35    IsStmMode,
36    /// High during the specified system time.
37    SysTimeEq(DcSysTime),
38    #[debug("PwmOut({})", _0.idx())]
39    /// PWM output of the specified transducer.
40    PwmOut(&'a Transducer),
41    #[debug("Direct({})", _0)]
42    /// High if `true`.
43    Direct(bool),
44}
45
46#[bitfield_struct::bitfield(u64)]
47#[derive(IntoBytes, Immutable)]
48pub(crate) struct DebugValue {
49    #[bits(56)]
50    pub(crate) value: u64,
51    #[bits(8)]
52    pub(crate) tag: u8,
53}
54
55impl From<GPIOOutputType<'_>> for DebugValue {
56    fn from(ty: GPIOOutputType<'_>) -> Self {
57        Self::new()
58            .with_value(match &ty {
59                GPIOOutputType::None
60                | GPIOOutputType::BaseSignal
61                | GPIOOutputType::Thermo
62                | GPIOOutputType::ForceFan
63                | GPIOOutputType::Sync
64                | GPIOOutputType::ModSegment
65                | GPIOOutputType::StmSegment
66                | GPIOOutputType::IsStmMode => 0,
67                GPIOOutputType::PwmOut(tr) => tr.idx() as _,
68                GPIOOutputType::ModIdx(idx) => *idx as _,
69                GPIOOutputType::StmIdx(idx) => *idx as _,
70                GPIOOutputType::SysTimeEq(time) => ec_time_to_sys_time(time) >> 9,
71                GPIOOutputType::Direct(v) => *v as _,
72            })
73            .with_tag(match &ty {
74                GPIOOutputType::None => 0x00,
75                GPIOOutputType::BaseSignal => 0x01,
76                GPIOOutputType::Thermo => 0x02,
77                GPIOOutputType::ForceFan => 0x03,
78                GPIOOutputType::Sync => 0x10,
79                GPIOOutputType::ModSegment => 0x20,
80                GPIOOutputType::ModIdx(_) => 0x21,
81                GPIOOutputType::StmSegment => 0x50,
82                GPIOOutputType::StmIdx(_) => 0x51,
83                GPIOOutputType::IsStmMode => 0x52,
84                GPIOOutputType::SysTimeEq(_) => 0x60,
85                GPIOOutputType::PwmOut(_) => 0xE0,
86                GPIOOutputType::Direct(_) => 0xF0,
87            })
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use crate::geometry::Point3;
94
95    use super::*;
96
97    #[test]
98    fn display() {
99        assert_eq!("None", format!("{:?}", GPIOOutputType::None));
100        assert_eq!("BaseSignal", format!("{:?}", GPIOOutputType::BaseSignal));
101        assert_eq!("Thermo", format!("{:?}", GPIOOutputType::Thermo));
102        assert_eq!("ForceFan", format!("{:?}", GPIOOutputType::ForceFan));
103        assert_eq!("Sync", format!("{:?}", GPIOOutputType::Sync));
104        assert_eq!("ModSegment", format!("{:?}", GPIOOutputType::ModSegment));
105        assert_eq!("ModIdx(1)", format!("{:?}", GPIOOutputType::ModIdx(1)));
106        assert_eq!("StmSegment", format!("{:?}", GPIOOutputType::StmSegment));
107        assert_eq!("StmIdx(1)", format!("{:?}", GPIOOutputType::StmIdx(1)));
108        assert_eq!("IsStmMode", format!("{:?}", GPIOOutputType::IsStmMode));
109        assert_eq!(
110            "PwmOut(0)",
111            format!(
112                "{:?}",
113                GPIOOutputType::PwmOut(&Transducer::new(Point3::origin()))
114            )
115        );
116        assert_eq!(
117            "Direct(true)",
118            format!("{:?}", GPIOOutputType::Direct(true))
119        );
120    }
121}