Skip to main content

pros_devices/adi/
digital.rs

1//! Digital input and output ADI devices
2
3use pros_core::bail_on;
4use pros_sys::PROS_ERR;
5
6use super::{AdiDevice, AdiDeviceType, AdiError, AdiPort};
7
8/// Represents the logic level of a digital pin.
9///
10/// On digital devices, logic levels represent the two possible voltage signals that define
11/// the state of a pin. This value is either [`High`] or [`Low`], depending on the intended
12/// state of the device.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum LogicLevel {
15    /// A high digital signal.
16    ///
17    /// ADI ports operate on 3.3V logic, so this value indicates a voltage of 3.3V or above.
18    High,
19
20    /// The low digital signal.
21    ///
22    /// ADI ports operate on 3.3V logic, so this value indicates a voltage below 3.3V.
23    Low,
24}
25
26impl LogicLevel {
27    /// Returns `true` if the level is [`High`].
28    pub const fn is_high(&self) -> bool {
29        match self {
30            Self::High => true,
31            Self::Low => false,
32        }
33    }
34
35    /// Returns `true` if the level is [`Low`].
36    pub const fn is_low(&self) -> bool {
37        match self {
38            Self::High => false,
39            Self::Low => true,
40        }
41    }
42}
43
44impl core::ops::Not for LogicLevel {
45    type Output = Self;
46
47    fn not(self) -> Self::Output {
48        match self {
49            Self::Low => Self::High,
50            Self::High => Self::Low,
51        }
52    }
53}
54
55/// Generic digital input ADI device.
56#[derive(Debug, Eq, PartialEq)]
57/// Generic digital input ADI device.
58pub struct AdiDigitalIn {
59    port: AdiPort,
60}
61
62impl AdiDigitalIn {
63    /// Create a digital input from an ADI port.
64    pub fn new(port: AdiPort) -> Result<Self, AdiError> {
65        bail_on!(PROS_ERR, unsafe {
66            pros_sys::ext_adi_port_set_config(
67                port.internal_expander_index(),
68                port.index(),
69                pros_sys::E_ADI_DIGITAL_IN,
70            )
71        });
72
73        Ok(Self { port })
74    }
75
76    /// Gets the current logic level of a digital input pin.
77    pub fn level(&self) -> Result<LogicLevel, AdiError> {
78        let value = bail_on!(PROS_ERR, unsafe {
79            pros_sys::ext_adi_digital_read(self.port.internal_expander_index(), self.port.index())
80        }) != 0;
81
82        Ok(match value {
83            true => LogicLevel::High,
84            false => LogicLevel::Low,
85        })
86    }
87
88    /// Returns `true` if the digital input's logic level level is [`LogicLevel::High`].
89    pub fn is_high(&self) -> Result<bool, AdiError> {
90        Ok(self.level()?.is_high())
91    }
92
93    /// Returns `true` if the digital input's logic level level is [`LogicLevel::Low`].
94    pub fn is_low(&self) -> Result<bool, AdiError> {
95        Ok(self.level()?.is_high())
96    }
97}
98
99impl AdiDevice for AdiDigitalIn {
100    type PortIndexOutput = u8;
101
102    fn port_index(&self) -> Self::PortIndexOutput {
103        self.port.index()
104    }
105
106    fn expander_port_index(&self) -> Option<u8> {
107        self.port.expander_index()
108    }
109
110    fn device_type(&self) -> AdiDeviceType {
111        AdiDeviceType::DigitalIn
112    }
113}
114
115/// Generic digital output ADI device.
116#[derive(Debug, Eq, PartialEq)]
117pub struct AdiDigitalOut {
118    port: AdiPort,
119}
120
121impl AdiDigitalOut {
122    /// Create a digital output from an [`AdiPort`].
123    pub fn new(port: AdiPort) -> Result<Self, AdiError> {
124        bail_on!(PROS_ERR, unsafe {
125            pros_sys::ext_adi_port_set_config(
126                port.internal_expander_index(),
127                port.index(),
128                pros_sys::E_ADI_DIGITAL_OUT,
129            )
130        });
131
132        Ok(Self { port })
133    }
134
135    /// Sets the digital logic level (high or low) of a pin.
136    pub fn set_level(&mut self, level: LogicLevel) -> Result<(), AdiError> {
137        bail_on!(PROS_ERR, unsafe {
138            pros_sys::ext_adi_digital_write(
139                self.port.internal_expander_index(),
140                self.port.index(),
141                level.is_high(),
142            )
143        });
144
145        Ok(())
146    }
147
148    /// Set the digital logic level to [`LogicLevel::High`]. Analagous to
149    /// [`Self::set_level(LogicLevel::High)`].
150    pub fn set_high(&mut self) -> Result<(), AdiError> {
151        self.set_level(LogicLevel::High)
152    }
153
154    /// Set the digital logic level to [`LogicLevel::Low`]. Analagous to
155    /// [`Self::set_level(LogicLevel::Low)`].
156    pub fn set_low(&mut self) -> Result<(), AdiError> {
157        self.set_level(LogicLevel::Low)
158    }
159}
160
161impl AdiDevice for AdiDigitalOut {
162    type PortIndexOutput = u8;
163
164    fn port_index(&self) -> Self::PortIndexOutput {
165        self.port.index()
166    }
167
168    fn expander_port_index(&self) -> Option<u8> {
169        self.port.expander_index()
170    }
171
172    fn device_type(&self) -> AdiDeviceType {
173        AdiDeviceType::DigitalOut
174    }
175}