1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! ADI Solenoid Pneumatic Control
use pros_core::bail_on;
use pros_sys::PROS_ERR;
use super::{digital::LogicLevel, AdiDevice, AdiDeviceType, AdiError, AdiPort};
/// Digital pneumatic solenoid valve.
#[derive(Debug, Eq, PartialEq)]
pub struct AdiSolenoid {
port: AdiPort,
level: LogicLevel,
}
impl AdiSolenoid {
/// Create an AdiSolenoid.
pub fn new(port: AdiPort) -> Result<Self, AdiError> {
bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_port_set_config(
port.internal_expander_index(),
port.index(),
pros_sys::E_ADI_DIGITAL_OUT,
)
});
Ok(Self {
port,
level: LogicLevel::Low,
})
}
/// Sets the digital logic level of the solenoid. [`LogicLevel::Low`] will close the solenoid,
/// and [`LogicLevel::High`] will open it.
pub fn set_level(&mut self, level: LogicLevel) -> Result<(), AdiError> {
self.level = level;
bail_on!(PROS_ERR, unsafe {
pros_sys::ext_adi_digital_write(
self.port.internal_expander_index(),
self.port.index(),
level.is_high(),
)
});
Ok(())
}
/// Returns the current [`LogicLevel`] of the solenoid's digital output state.
pub const fn level(&self) -> LogicLevel {
self.level
}
/// Returns `true` if the solenoid is open.
pub const fn is_open(&self) -> LogicLevel {
self.level
}
/// Returns `true` if the solenoid is closed.
pub const fn is_closed(&self) -> LogicLevel {
self.level
}
/// Open the solenoid, allowing air pressure through the "open" valve.
pub fn open(&mut self) -> Result<(), AdiError> {
self.set_level(LogicLevel::High)
}
/// Close the solenoid.
///
/// - On single-acting solenoids (e.g. SY113-SMO-PM3-F), this will simply block air pressure
/// through the "open" valve.
/// - On double-acting solenoids (e.g. SYJ3120-SMO-M3-F), this will block air pressure through
/// the "open" valve and allow air pressure into the "close" valve.
pub fn close(&mut self) -> Result<(), AdiError> {
self.set_level(LogicLevel::Low)
}
/// Toggle the solenoid's state between open and closed.
pub fn toggle(&mut self) -> Result<(), AdiError> {
self.set_level(!self.level)
}
}
impl AdiDevice for AdiSolenoid {
type PortIndexOutput = u8;
fn port_index(&self) -> Self::PortIndexOutput {
self.port.index()
}
fn expander_port_index(&self) -> Option<u8> {
self.port.expander_index()
}
fn device_type(&self) -> AdiDeviceType {
AdiDeviceType::DigitalOut
}
}