Skip to main content

ev3dev_rs/pupdevices/
infrared_sensor.rs

1use std::collections::HashSet;
2
3use crate::{
4    attribute::AttributeName,
5    error::{Ev3Error, Ev3Result},
6    parameters::{Button, SensorPort},
7    sensor_driver::{SensorDriver, SensorMode, SensorType},
8};
9
10/// Stock EV3 Infrared Sensor
11///
12/// Note that this sensor does not support direct measurement of distance
13/// and that the `proximity()` percentage does not scale linearly with distance.
14///
15/// If you want to get an accurate distance measurement, you should use an`UltrasonicSensor`.
16pub struct InfraredSensor {
17    driver: SensorDriver,
18}
19
20impl InfraredSensor {
21    /// Find an `InfraredSensor` on the given port.
22    ///
23    /// Will return `SensorNotFound` if no sensor is found
24    /// or `IncorrectSensorType` if the found sensor is not an `InfraredSensor`.
25    pub fn new(port: SensorPort) -> Ev3Result<Self> {
26        let driver = SensorDriver::new(SensorType::Infrared, port)?;
27        Ok(Self { driver })
28    }
29
30    /// Get the proximity value of the sensor as a percentage (0 to 100).
31    ///
32    /// 100% is approximately 70cm/27in.
33    ///
34    /// Note that this sensor does not support direct measurement of distance
35    /// and that the percentage does not scale linearly with distance.
36    ///
37    /// If you want to get an accurate distance measurement, you should use an `UltrasonicSensor`.
38    pub async fn proximity(&self) -> Ev3Result<u8> { 
39        self.driver.set_mode(SensorMode::InfraredProximity).await?;
40        
41        Ok(self.driver.read_attribute(AttributeName::Value0).await?.parse()?)
42    }
43
44    #[inline]
45    /// Get a `HashSet` of buttons currently pressed on the remote control channel 1.
46    ///
47    /// Note that the set will be empty if three or more buttons are pressed.
48    pub async fn get_remote_channel_1_buttons(&self) -> Ev3Result<HashSet<Button>> {
49        self.get_remote_buttons(AttributeName::Value0).await
50    }
51
52    /// Get a `HashSet` of buttons currently pressed on the remote control channel 2.
53    ///
54    /// Note that the set will be empty if three or more buttons are pressed.
55    #[inline]
56    pub async fn get_remote_channel_2_buttons(&self) -> Ev3Result<HashSet<Button>> {
57        self.get_remote_buttons(AttributeName::Value1).await
58    }
59
60    /// Get a `HashSet` of buttons currently pressed on the remote control channel 3.
61    ///
62    /// Note that the set will be empty if three or more buttons are pressed.
63    #[inline]
64    pub async fn get_remote_channel_3_buttons(&self) -> Ev3Result<HashSet<Button>> {
65        self.get_remote_buttons(AttributeName::Value2).await
66    }
67
68    /// Get a `HashSet` of buttons currently pressed on the remote control channel 4.
69    ///
70    /// Note that the set will be empty if three or more buttons are pressed.
71    #[inline]
72    pub async fn get_remote_channel_4_buttons(&self) -> Ev3Result<HashSet<Button>> {
73        self.get_remote_buttons(AttributeName::Value3).await
74    }
75
76    /// Seeks a remote control in beacon mode on channel 1.
77    ///
78    /// The first value is heading (-25 to 25),
79    /// and the second value is distance as a percentage (-128 and 0 to 100).
80    ///
81    /// The distance is -128 when the remote is out of range.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// let (heading, distance) = infrared_sensor.seek_channel_1().await?;
87    /// ```
88    #[inline]
89    pub async fn seek_channel_1(&self) -> Ev3Result<(i8, i8)> {
90        self.seek(AttributeName::Value0, AttributeName::Value1).await
91    }
92
93    /// Seeks a remote control in beacon mode on channel 2.
94    ///
95    /// The first value is heading (-25 to 25),
96    /// and the second value is distance as a percentage (-128 and 0 to 100).
97    ///
98    /// The distance is -128 when the remote is out of range.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// let (heading, distance) = infrared_sensor.seek_channel_2().await?;
104    /// ```
105    #[inline]
106    pub async fn seek_channel_2(&self) -> Ev3Result<(i8, i8)> {
107        self.seek(AttributeName::Value2, AttributeName::Value3).await
108    }
109
110    /// Seeks a remote control in beacon mode on channel 3.
111    ///
112    /// The first value is heading (-25 to 25),
113    /// and the second value is distance as a percentage (-128 and 0 to 100).
114    ///
115    /// The distance is -128 when the remote is out of range.
116    ///
117    /// # Examples
118    ///
119    /// ``` no_run
120    /// let (heading, distance) = infrared_sensor.seek_channel_3().await?;
121    /// ```
122    #[inline]
123    pub async fn seek_channel_3(&self) -> Ev3Result<(i8, i8)> {
124        self.seek(AttributeName::Value4, AttributeName::Value5).await
125    }
126
127    /// Seeks a remote control in beacon mode on channel 4.
128    ///
129    /// The first value is heading (-25 to 25),
130    /// and the second value is distance as a percentage (-128 and 0 to 100).
131    ///
132    /// The distance is -128 when the remote is out of range.
133    ///
134    /// # Examples
135    ///
136    /// ``` no_run
137    /// let (heading, distance) = infrared_sensor.seek_channel_4().await?;
138    /// ```
139    #[inline]
140    pub async fn seek_channel_4(&self) -> Ev3Result<(i8, i8)> {
141        self.seek(AttributeName::Value6, AttributeName::Value7).await
142    }
143
144    async fn get_remote_buttons(&self, attr: AttributeName) -> Ev3Result<HashSet<Button>> {
145
146        self.driver.set_mode(SensorMode::InfraredRemote).await?;
147        
148
149        let val = self.driver.read_attribute(attr).await?;
150        let mut set = HashSet::new();
151
152        match val.parse::<u8>()? {
153            0 => (),
154            1 => _ = set.insert(Button::RedUp),
155            2 => _ = set.insert(Button::RedDown),
156            3 => _ = set.insert(Button::BlueUp),
157            4 => _ = set.insert(Button::BlueDown),
158            5 => {
159                _ = set.insert(Button::RedUp);
160                _ = set.insert(Button::BlueUp);
161            }
162            6 => {
163                _ = set.insert(Button::RedUp);
164                _ = set.insert(Button::BlueDown);
165            }
166            7 => {
167                _ = set.insert(Button::RedDown);
168                _ = set.insert(Button::BlueUp);
169            }
170            8 => {
171                _ = set.insert(Button::RedDown);
172                _ = set.insert(Button::BlueDown);
173            }
174            9 => _ = set.insert(Button::BeaconOn),
175            10 => {
176                _ = set.insert(Button::RedUp);
177                _ = set.insert(Button::RedDown);
178            }
179            11 => {
180                _ = set.insert(Button::BlueUp);
181                _ = set.insert(Button::BlueDown);
182            }
183            _ => {
184                return Err(Ev3Error::InvalidValue {
185                    func: "InfraredSensor::get_remote_buttons".into(),
186                    value: val,
187                });
188            }
189        };
190
191        Ok(set)
192    }
193
194    async fn seek(&self, attr1: AttributeName, attr2: AttributeName) -> Ev3Result<(i8, i8)> {
195
196        self.driver.set_mode(SensorMode::InfraredSeek).await?;
197        
198        Ok((
199            self.driver.read_attribute(attr1).await?.parse()?,
200            self.driver.read_attribute(attr2).await?.parse()?,
201        ))
202    }
203}