vex_rt/adi/
gyro.rs

1use alloc::string::ToString;
2
3use crate::{
4    bindings,
5    error::{get_errno, Error},
6    rtos::DataSource,
7};
8
9/// A struct which represents a V5 ADI port configured to be an ADI gyro.
10pub struct AdiGyro {
11    port: bindings::ext_adi_gyro_t,
12}
13impl AdiGyro {
14    /// Initializes a gyroscope on the given port.
15    /// If the given port has not previously been configured as a gyro, then
16    /// this function starts a 1300 ms calibration period.
17    ///
18    /// # Safety
19    ///
20    /// This function is unsafe because it allows the user to create multiple
21    /// mutable references to the same ADI gyro. You likely want to
22    /// implement [`Robot::new()`](crate::robot::Robot::new()) instead.
23    pub unsafe fn new(
24        adi_port: u8,
25        multiplier: f64,
26        extender_port: u8,
27    ) -> Result<Self, AdiGyroError> {
28        match bindings::ext_adi_gyro_init(extender_port, adi_port, multiplier) {
29            bindings::PROS_ERR_ => Err(AdiGyroError::from_errno()),
30            x => Ok(Self { port: x }),
31        }
32    }
33
34    /// Resets the gyroscope value to zero.
35    pub fn reset(&mut self) -> Result<(), AdiGyroError> {
36        match unsafe { bindings::ext_adi_gyro_reset(self.port) } {
37            bindings::PROS_ERR_ => Err(AdiGyroError::from_errno()),
38            _ => Ok(()),
39        }
40    }
41
42    /// Gets the current gyro angle in tenths of a degree.
43    /// Unless a multiplier is applied to the gyro, the return value will be a
44    /// whole number representing the number of degrees of rotation times 10.
45    /// There are 360 degrees in a circle, thus the gyro will return 3600 for
46    /// one whole rotation.
47    pub fn get(&self) -> Result<f64, AdiGyroError> {
48        let out = unsafe { bindings::ext_adi_gyro_get(self.port) };
49        if out == bindings::PROS_ERR_F_ {
50            Err(AdiGyroError::from_errno())
51        } else {
52            Ok(out)
53        }
54    }
55}
56
57impl DataSource for AdiGyro {
58    type Data = f64;
59
60    type Error = AdiGyroError;
61
62    fn read(&self) -> Result<Self::Data, Self::Error> {
63        self.get()
64    }
65}
66
67impl Drop for AdiGyro {
68    fn drop(&mut self) {
69        if let bindings::PROS_ERR_ = unsafe { bindings::ext_adi_gyro_shutdown(self.port) } {
70            panic!(
71                "failed to shutdown ADI gyro: {:?}",
72                AdiGyroError::from_errno()
73            );
74        }
75    }
76}
77
78/// Represents possible errors for ADI gyro operations.
79#[derive(Debug)]
80pub enum AdiGyroError {
81    /// Port is out of range (1-8).
82    PortOutOfRange,
83    /// Port cannot be configured as an ADI encoder.
84    PortNotAdiEncoder,
85    /// Unknown error.
86    Unknown(i32),
87}
88impl AdiGyroError {
89    fn from_errno() -> Self {
90        match get_errno() {
91            libc::ENXIO => Self::PortOutOfRange,
92            libc::EADDRINUSE => Self::PortNotAdiEncoder,
93            x => Self::Unknown(x),
94        }
95    }
96}
97impl From<AdiGyroError> for Error {
98    fn from(err: AdiGyroError) -> Self {
99        match err {
100            AdiGyroError::PortOutOfRange => Error::Custom("port out of range".to_string()),
101            AdiGyroError::PortNotAdiEncoder => Error::Custom("port not an adi gyro".to_string()),
102            AdiGyroError::Unknown(n) => Error::System(n),
103        }
104    }
105}