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}