vex_rt/
smart_port.rs

1//! SmartPort.
2
3use crate::{
4    adi::AdiExpander,
5    bindings,
6    distance::DistanceSensor,
7    error::Error,
8    imu::InertialSensor,
9    motor::{EncoderUnits, Gearset, Motor, MotorError},
10    rotation::{RotationSensor, RotationSensorError},
11    serial::Serial,
12};
13use core::convert::{TryFrom, TryInto};
14
15/// A struct which represents an unconfigured smart port.
16pub struct SmartPort {
17    port: u8,
18}
19
20impl SmartPort {
21    /// Constructs a new smart port.
22    ///
23    /// # Safety
24    ///
25    /// This function is unsafe because it allows the user to create multiple
26    /// mutable references to a V5 smart port. You likely want to implement
27    /// [`Robot::new()`](crate::robot::Robot::new()) instead.
28    pub unsafe fn new(port: u8) -> Self {
29        assert!(
30            (1..22).contains(&port),
31            "Cannot construct a smart port on port {}",
32            port
33        );
34        Self { port }
35    }
36
37    #[inline]
38    /// Checks the type of device currently connected to the port.
39    pub fn plugged_type(&self) -> DeviceType {
40        unsafe { smart_port_type(self.port) }
41    }
42
43    /// Converts a `SmartPort` into a [`Motor`](crate::motor::Motor).
44    pub fn into_motor(
45        self,
46        gearset: Gearset,
47        encoder_units: EncoderUnits,
48        reverse: bool,
49    ) -> Result<Motor, MotorError> {
50        (self, gearset, encoder_units, reverse).try_into()
51    }
52
53    /// Converts a `SmartPort` into a [`Serial`].
54    pub fn into_serial(self, baudrate: i32) -> Result<Serial, Error> {
55        (self, baudrate).try_into()
56    }
57
58    /// Converts a `SmartPort` into an [`AdiExpander`](crate::adi::AdiExpander).
59    pub fn into_expander(self) -> AdiExpander {
60        self.into()
61    }
62
63    /// Converts a `SmartPort` into a
64    /// [`DistanceSensor`](crate::distance::DistanceSensor).
65    pub fn into_distance(self) -> DistanceSensor {
66        self.into()
67    }
68
69    /// Converts a `SmartPort` into a
70    /// [`InertialSensor`](crate::imu::InertialSensor).
71    pub fn into_imu(self) -> InertialSensor {
72        self.into()
73    }
74
75    /// Converts a `SmartPort` into a
76    /// [`RotationSensor`](crate::rotation::RotationSensor).
77    #[inline]
78    pub fn into_rotation(self, reversed: bool) -> Result<RotationSensor, RotationSensorError> {
79        (self, reversed).try_into()
80    }
81}
82
83impl TryFrom<(SmartPort, Gearset, EncoderUnits, bool)> for Motor {
84    type Error = MotorError;
85
86    fn try_from(
87        (port, gearset, encoder_units, reverse): (SmartPort, Gearset, EncoderUnits, bool),
88    ) -> Result<Self, Self::Error> {
89        unsafe { Self::new(port.port, gearset, encoder_units, reverse) }
90    }
91}
92
93impl TryFrom<(SmartPort, i32)> for Serial {
94    type Error = Error;
95
96    fn try_from((port, baudrate): (SmartPort, i32)) -> Result<Self, Self::Error> {
97        unsafe { Self::new(port.port, baudrate) }
98    }
99}
100
101impl From<SmartPort> for AdiExpander {
102    fn from(port: SmartPort) -> Self {
103        unsafe { AdiExpander::new(port.port) }
104    }
105}
106
107impl From<SmartPort> for DistanceSensor {
108    fn from(port: SmartPort) -> Self {
109        unsafe { DistanceSensor::new(port.port) }
110    }
111}
112impl From<SmartPort> for InertialSensor {
113    fn from(port: SmartPort) -> Self {
114        unsafe { InertialSensor::new(port.port) }
115    }
116}
117
118impl TryFrom<(SmartPort, bool)> for RotationSensor {
119    type Error = RotationSensorError;
120
121    #[inline]
122    fn try_from((port, reversed): (SmartPort, bool)) -> Result<Self, Self::Error> {
123        unsafe { RotationSensor::new(port.port, reversed) }
124    }
125}
126
127/// Represents the type of device plugged into a smart port.
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum DeviceType {
130    /// No device.
131    None,
132
133    /// V5 Smart Motor.
134    Motor,
135
136    /// V5 Rotation Sensor
137    Rotation,
138
139    /// V5 Inertial Sensor
140    Imu,
141
142    /// V5 Distance Sensor.
143    Distance,
144
145    /// V5 Robot Radio.
146    Radio,
147
148    /// V5 Vision Sensor.
149    Vision,
150
151    /// V5 3-Wire Expander.
152    Adi,
153
154    /// V5 Optical Sensor.
155    Optical,
156
157    /// Generic serial mode.
158    Serial,
159
160    /// Undefined sensor type.
161    Undefined,
162
163    /// Unrecognized value from PROS/vexOS.
164    Unknown(u32),
165}
166
167impl From<bindings::v5_device_e_t> for DeviceType {
168    fn from(t: bindings::v5_device_e_t) -> Self {
169        match t {
170            bindings::v5_device_e_E_DEVICE_NONE => Self::None,
171            bindings::v5_device_e_E_DEVICE_MOTOR => Self::Motor,
172            bindings::v5_device_e_E_DEVICE_ROTATION => Self::Rotation,
173            bindings::v5_device_e_E_DEVICE_IMU => Self::Imu,
174            bindings::v5_device_e_E_DEVICE_DISTANCE => Self::Distance,
175            bindings::v5_device_e_E_DEVICE_RADIO => Self::Radio,
176            bindings::v5_device_e_E_DEVICE_VISION => Self::Vision,
177            bindings::v5_device_e_E_DEVICE_ADI => Self::Adi,
178            bindings::v5_device_e_E_DEVICE_OPTICAL => Self::Optical,
179            bindings::v5_device_e_E_DEVICE_GENERIC => Self::Serial,
180            bindings::v5_device_e_E_DEVICE_UNDEFINED => Self::Undefined,
181            _ => Self::Unknown(t),
182        }
183    }
184}
185
186/// Checks the type of device currently connected to a smart port.
187///
188/// # Safety
189/// This is unsafe because it may be unsequenced relative to operations on the
190/// smart port. Prefer [`SmartPort::plugged_type()`] instead.
191pub unsafe fn smart_port_type(port: u8) -> DeviceType {
192    bindings::registry_get_plugged_type(port - 1).into()
193}