vex_rt/adi/
analog.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 analog input.
8pub struct AdiAnalog {
9    port: u8,
10    expander_port: u8,
11}
12
13impl AdiAnalog {
14    /// Initializes an ADI analog reader on an ADI port.
15    ///
16    /// # Safety
17    ///
18    /// This function is unsafe because it allows the user to create multiple
19    /// mutable references to the same ADI analog reader. You likely want to
20    /// implement [`Robot::new()`](crate::robot::Robot::new()) instead.
21    pub unsafe fn new(port: u8, expander_port: u8) -> Result<Self, AdiAnalogError> {
22        match bindings::ext_adi_port_set_config(
23            expander_port,
24            port,
25            bindings::adi_port_config_e_E_ADI_ANALOG_IN,
26        ) {
27            bindings::PROS_ERR_ => Err(AdiAnalogError::from_errno()),
28            _ => Ok(Self {
29                port,
30                expander_port,
31            }),
32        }
33    }
34
35    /// Calibrates the analog sensor on the specified channel.
36
37    /// This method assumes that the true sensor value is not actively changing
38    /// at this time and computes an average from approximately 500 samples, 1
39    /// ms apart, for a 0.5 s period of calibration. The average value thus
40    /// calculated is returned and stored for later calls to the
41    /// ext_adi_analog_read_calibrated and ext_adi_analog_read_calibrated_HR
42    /// functions. These functions will return the difference between this value
43    /// and the current sensor value when called.
44
45    /// Do not use this function when the sensor value might be unstable (gyro
46    /// rotation, accelerometer movement).
47
48    /// Returns: The average sensor value computed by this function.
49    pub fn calibrate(&mut self) -> Result<i32, AdiAnalogError> {
50        match unsafe { bindings::ext_adi_analog_calibrate(self.expander_port, self.port) } {
51            bindings::PROS_ERR_ => Err(AdiAnalogError::from_errno()),
52            x => Ok(x),
53        }
54    }
55
56    /// Reads an analog input channel and returns the 12-bit value.
57
58    /// The value returned is undefined if the analog pin has been switched to a
59    /// different mode. The meaning of the returned value varies depending on
60    /// the sensor attached.
61
62    /// Returns: The analog sensor value, where a value
63    /// of 0 reflects an input voltage of nearly 0 V and a value of 4095
64    /// reflects an input voltage of nearly 5 V
65    pub fn read(&self) -> Result<i32, AdiAnalogError> {
66        match unsafe { bindings::ext_adi_analog_read(self.expander_port, self.port) } {
67            bindings::PROS_ERR_ => Err(AdiAnalogError::from_errno()),
68            x => Ok(x),
69        }
70    }
71
72    /// Reads the calibrated value of an analog input channel.
73
74    /// The [`AdiAnalog::read_calibrated()`](crate::adi::analog::AdiAnalog::
75    /// read_calibrated()) function must be run first on that channel.
76    /// This function is inappropriate for sensor values intended for
77    /// integration, as round-off error can accumulate causing drift over time.
78    /// Use [`AdiAnalog::read_calibrated_hr()`](crate::adi::analog::AdiAnalog::
79    /// read_calibrated_hr()) instead.
80
81    /// Returns: The difference of the sensor value from its calibrated default
82    /// from -4095 to 4095.
83    pub fn read_calibrated(&self) -> Result<i32, AdiAnalogError> {
84        match unsafe { bindings::ext_adi_analog_read_calibrated(self.expander_port, self.port) } {
85            bindings::PROS_ERR_ => Err(AdiAnalogError::from_errno()),
86            x => Ok(x),
87        }
88    }
89
90    /// Reads the calibrated value of an analog input channel 1-8 with enhanced
91    /// precision.
92
93    /// The [`AdiAnalog::read_calibrated()`](crate::adi::analog::AdiAnalog::
94    /// read_calibrated()) function must be run first. This is intended for
95    /// integrated sensor values such as gyros and accelerometers
96    /// to reduce drift due to round-off, and should not be used on a sensor
97    /// such as a line tracker or potentiometer.
98
99    /// The value returned actually has 16 bits of “precision”, even though the
100    /// ADC only reads 12 bits, so that errors induced by the average value
101    /// being between two values come out in the wash when integrated over time.
102    /// Think of the value as the true value times 16.
103
104    /// Returns: The difference of the sensor value from its calibrated default
105    /// from -16384 to 16384.
106    pub fn read_calibrated_hr(&self) -> Result<i32, AdiAnalogError> {
107        match unsafe { bindings::ext_adi_analog_read_calibrated_HR(self.expander_port, self.port) }
108        {
109            bindings::PROS_ERR_ => Err(AdiAnalogError::from_errno()),
110            x => Ok(x),
111        }
112    }
113}
114
115impl DataSource for AdiAnalog {
116    type Data = i32;
117
118    type Error = AdiAnalogError;
119
120    fn read(&self) -> Result<Self::Data, Self::Error> {
121        self.read()
122    }
123}
124
125/// Represents possible errors for ADI analog operations.
126#[derive(Debug)]
127pub enum AdiAnalogError {
128    /// Ports are out of range (1-8).
129    PortsOutOfRange,
130    /// Ports cannot be configured as an ADI Analog input.
131    PortsNotAnalogInput,
132    /// Unknown error.
133    Unknown(i32),
134}
135
136impl AdiAnalogError {
137    fn from_errno() -> Self {
138        match get_errno() {
139            libc::ENXIO => Self::PortsOutOfRange,
140            libc::EADDRINUSE => Self::PortsNotAnalogInput,
141            x => Self::Unknown(x),
142        }
143    }
144}
145
146impl From<AdiAnalogError> for Error {
147    fn from(err: AdiAnalogError) -> Self {
148        match err {
149            AdiAnalogError::PortsOutOfRange => Error::Custom("ports out of range".into()),
150            AdiAnalogError::PortsNotAnalogInput => {
151                Error::Custom("ports not an adi analog input".into())
152            }
153            AdiAnalogError::Unknown(n) => Error::System(n),
154        }
155    }
156}