1use pros_core::{bail_on, error::PortError, map_errno};
4use pros_sys::{adi_port_config_e_t, E_ADI_ERR, PROS_ERR};
5use snafu::Snafu;
6
7pub mod analog;
9pub mod digital;
10pub mod pwm;
11
12pub mod encoder;
13pub mod gyro;
14pub mod linetracker;
15pub mod motor;
16pub mod potentiometer;
17pub mod solenoid;
18pub mod switch;
19pub mod ultrasonic;
20
21pub use analog::AdiAnalogIn;
22pub use digital::{AdiDigitalIn, AdiDigitalOut};
23pub use encoder::AdiEncoder;
24pub use gyro::AdiGyro;
25pub use linetracker::AdiLineTracker;
26pub use motor::AdiMotor;
27pub use potentiometer::AdiPotentiometer;
28pub use solenoid::AdiSolenoid;
29pub use ultrasonic::AdiUltrasonic;
30
31#[derive(Debug, Eq, PartialEq)]
33pub struct AdiPort {
34 index: u8,
38
39 expander_index: Option<u8>,
43}
44
45impl AdiPort {
46 pub const unsafe fn new(index: u8, expander_index: Option<u8>) -> Self {
54 Self {
55 index,
56 expander_index,
57 }
58 }
59
60 pub const fn index(&self) -> u8 {
64 self.index
65 }
66
67 pub const fn expander_index(&self) -> Option<u8> {
70 self.expander_index
71 }
72
73 pub(crate) fn internal_expander_index(&self) -> u8 {
76 self.expander_index
77 .unwrap_or(pros_sys::adi::INTERNAL_ADI_PORT as u8)
78 }
79
80 pub fn configured_type(&self) -> Result<AdiDeviceType, AdiError> {
82 bail_on!(PROS_ERR, unsafe {
83 pros_sys::ext_adi::ext_adi_port_get_config(self.internal_expander_index(), self.index())
84 })
85 .try_into()
86 }
87}
88
89pub trait AdiDevice {
91 type PortIndexOutput;
93
94 fn port_index(&self) -> Self::PortIndexOutput;
98
99 fn expander_port_index(&self) -> Option<u8>;
103
104 fn device_type(&self) -> AdiDeviceType;
106}
107
108#[repr(i32)]
110#[derive(Debug, Clone, Copy, Eq, PartialEq)]
111pub enum AdiDeviceType {
112 AnalogIn = pros_sys::adi::E_ADI_ANALOG_IN,
114
115 PwmOut = pros_sys::adi::E_ADI_ANALOG_OUT,
120
121 DigitalIn = pros_sys::adi::E_ADI_DIGITAL_IN,
123
124 DigitalOut = pros_sys::adi::E_ADI_DIGITAL_OUT,
126
127 LegacyGyro = pros_sys::adi::E_ADI_LEGACY_GYRO,
129
130 LegacyServo = pros_sys::adi::E_ADI_LEGACY_SERVO,
132
133 LegacyPwm = pros_sys::adi::E_ADI_LEGACY_PWM,
139
140 LegacyEncoder = pros_sys::E_ADI_LEGACY_ENCODER,
142
143 LegacyUltrasonic = pros_sys::E_ADI_LEGACY_ULTRASONIC,
145}
146
147impl TryFrom<adi_port_config_e_t> for AdiDeviceType {
148 type Error = AdiError;
149
150 fn try_from(value: adi_port_config_e_t) -> Result<Self, Self::Error> {
151 bail_on!(E_ADI_ERR, value);
152
153 match value {
154 pros_sys::E_ADI_ANALOG_IN => Ok(AdiDeviceType::AnalogIn),
155 pros_sys::E_ADI_ANALOG_OUT => Ok(AdiDeviceType::PwmOut),
156 pros_sys::E_ADI_DIGITAL_IN => Ok(AdiDeviceType::DigitalIn),
157 pros_sys::E_ADI_DIGITAL_OUT => Ok(AdiDeviceType::DigitalOut),
158
159 pros_sys::E_ADI_LEGACY_GYRO => Ok(AdiDeviceType::LegacyGyro),
160
161 pros_sys::E_ADI_LEGACY_SERVO => Ok(AdiDeviceType::LegacyServo),
162 pros_sys::E_ADI_LEGACY_PWM => Ok(AdiDeviceType::LegacyPwm),
163
164 pros_sys::E_ADI_LEGACY_ENCODER => Ok(AdiDeviceType::LegacyEncoder),
165 pros_sys::E_ADI_LEGACY_ULTRASONIC => Ok(AdiDeviceType::LegacyUltrasonic),
166
167 _ => Err(AdiError::UnknownDeviceType),
168 }
169 }
170}
171
172impl From<AdiDeviceType> for adi_port_config_e_t {
173 fn from(value: AdiDeviceType) -> Self {
174 value as _
175 }
176}
177
178#[derive(Debug, Snafu)]
179pub enum AdiError {
181 AlreadyInUse,
183
184 UnknownDeviceType,
186
187 PortNotConfigured,
189
190 ExpanderPortMismatch,
192
193 InvalidValue,
195
196 #[snafu(display("{source}"), context(false))]
197 Port {
199 source: PortError,
201 },
202}
203
204map_errno! {
205 AdiError {
206 EACCES => Self::AlreadyInUse,
207 EADDRINUSE => Self::PortNotConfigured,
208 EINVAL => Self::InvalidValue,
209 }
210 inherit PortError;
211}