vex_rt/adi/
encoder.rs

1use crate::{
2    bindings,
3    error::{get_errno, Error},
4    rtos::DataSource,
5};
6
7/// A struct which represents a V5 ADI port configured as an ADI encoder.
8pub struct AdiEncoder {
9    port: bindings::ext_adi_encoder_t,
10}
11
12impl AdiEncoder {
13    /// Initializes and enables a quadrature encoder on two ADI ports.
14    ///
15    /// # Safety
16    ///
17    /// This function is unsafe because it allows the user to create multiple
18    /// mutable references to the same ADI encoder. You likely want to
19    /// implement [`Robot::new()`](crate::robot::Robot::new()) instead.
20    pub unsafe fn new(
21        top_port: u8,
22        bottom_port: u8,
23        reverse: bool,
24        extender_port: u8,
25    ) -> Result<AdiEncoder, AdiEncoderError> {
26        match bindings::ext_adi_encoder_init(extender_port, top_port, bottom_port, reverse) {
27            bindings::PROS_ERR_ => Err(AdiEncoderError::from_errno()),
28            x => Ok(AdiEncoder { port: x }),
29        }
30    }
31
32    /// Resets the encoder to zero.
33    /// It is safe to use this method while an encoder is enabled. It is not
34    /// necessary to call this method before stopping or starting an encoder.
35    pub fn reset(&mut self) -> Result<(), AdiEncoderError> {
36        match unsafe { bindings::ext_adi_encoder_reset(self.port) } {
37            bindings::PROS_ERR_ => Err(AdiEncoderError::from_errno()),
38            _ => Ok(()),
39        }
40    }
41
42    /// Gets the number of ticks recorded by the encoder.
43    /// There are 360 ticks in one revolution.
44    pub fn get(&self) -> Result<i32, AdiEncoderError> {
45        match unsafe { bindings::ext_adi_encoder_get(self.port) } {
46            bindings::PROS_ERR_ => Err(AdiEncoderError::from_errno()),
47            x => Ok(x),
48        }
49    }
50}
51
52impl DataSource for AdiEncoder {
53    type Data = i32;
54
55    type Error = AdiEncoderError;
56
57    fn read(&self) -> Result<Self::Data, Self::Error> {
58        self.get()
59    }
60}
61
62impl Drop for AdiEncoder {
63    fn drop(&mut self) {
64        if let bindings::PROS_ERR_ = unsafe { bindings::ext_adi_encoder_shutdown(self.port) } {
65            panic!(
66                "failed to shutdown ADI encoder: {:?}",
67                AdiEncoderError::from_errno()
68            );
69        }
70    }
71}
72
73/// Represents possible errors for ADI encoder operations.
74#[derive(Debug)]
75pub enum AdiEncoderError {
76    /// Ports are out of range (1-8).
77    PortsOutOfRange,
78    /// Ports cannot be configured as an ADI encoder.
79    PortsNotAdiEncoder,
80    /// Ports are from non matching extenders.
81    PortNonMatchingExtenders,
82    /// Unknown error.
83    Unknown(i32),
84}
85
86impl AdiEncoderError {
87    fn from_errno() -> Self {
88        match get_errno() {
89            libc::ENXIO => Self::PortsOutOfRange,
90            libc::ENODEV => Self::PortsNotAdiEncoder,
91            x => Self::Unknown(x),
92        }
93    }
94}
95
96impl From<AdiEncoderError> for Error {
97    fn from(err: AdiEncoderError) -> Self {
98        match err {
99            AdiEncoderError::PortsOutOfRange => Error::Custom("ports out of range".into()),
100            AdiEncoderError::PortsNotAdiEncoder => Error::Custom("ports not an adi encoder".into()),
101            AdiEncoderError::PortNonMatchingExtenders => {
102                Error::Custom("ports from non-matching extenders".into())
103            }
104            AdiEncoderError::Unknown(n) => Error::System(n),
105        }
106    }
107}