ev3dev_lang_rust/sensors/
infrared_sensor.rs1use super::{Sensor, SensorPort};
4use crate::{sensor_mode, Attribute, Device, Driver, Ev3Error, Ev3Result};
5use std::cell::RefCell;
6use std::collections::HashSet;
7use std::fmt;
8use std::rc::Rc;
9
10#[derive(Debug, Clone, Device, Sensor)]
12pub struct InfraredSensor {
13 driver: Driver,
14}
15
16impl InfraredSensor {
17 fn new(driver: Driver) -> Self {
18 Self { driver }
19 }
20
21 findable!(
22 "lego-sensor",
23 ["lego-ev3-ir"],
24 SensorPort,
25 "InfraredSensor",
26 "in"
27 );
28
29 sensor_mode!(
30 "IR-PROX",
31 MODE_IR_PROX,
32 "Proximity",
33 set_mode_ir_prox,
34 is_mode_ir_prox
35 );
36 sensor_mode!(
37 "IR-SEEK",
38 MODE_IR_SEEK,
39 "IR Seeker",
40 set_mode_ir_seek,
41 is_mode_ir_seek
42 );
43 sensor_mode!(
44 "IR-REMOTE",
45 MODE_IR_REMOTE,
46 "IR Remote Control",
47 set_mode_ir_remote,
48 is_mode_ir_remote
49 );
50 sensor_mode!(
51 "IR-REM-A",
52 MODE_IR_REM_A,
53 "IR Remote Control",
54 set_mode_ir_rem_a,
55 is_mode_ir_rem_a
56 );
57 sensor_mode!(
58 "IR-S-ALT",
59 MODE_IR_S_ALT,
60 "Alternate IR Seeker ???",
61 set_mode_ir_s_alt,
62 is_mode_ir_s_alt
63 );
64 sensor_mode!(
65 "IR-CAL",
66 MODE_IR_CAL,
67 "Calibration ???",
68 set_mode_ir_cal,
69 is_mode_ir_cal
70 );
71
72 pub fn get_distance(&self) -> Ev3Result<i32> {
74 self.get_value0()
75 }
76}
77
78struct RemoteControlHelper {
79 last_buttons: i32,
80 pressed_buttons: HashSet<String>,
81}
82
83impl RemoteControlHelper {
84 fn new() -> RemoteControlHelper {
85 RemoteControlHelper {
86 last_buttons: 0,
87 pressed_buttons: HashSet::new(),
88 }
89 }
90
91 fn contains(&self, button: &str) -> bool {
92 self.pressed_buttons.contains(button)
93 }
94}
95
96#[derive(Clone)]
98pub struct RemoteControl {
99 sensor: InfraredSensor,
100 channel: u8,
101 helper: Rc<RefCell<RemoteControlHelper>>,
102}
103
104impl fmt::Debug for RemoteControl {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 f.debug_struct("RemoteControl")
108 .field("sensor", &self.sensor)
109 .field("channel", &self.channel)
110 .finish()
111 }
112}
113
114impl RemoteControl {
115 pub fn new(sensor: InfraredSensor, channel: u8) -> Ev3Result<RemoteControl> {
117 sensor.set_mode_ir_remote()?;
118
119 Ok(RemoteControl {
120 sensor,
121 channel: u8::max(1, u8::min(4, channel)) - 1,
122 helper: Rc::new(RefCell::new(RemoteControlHelper::new())),
123 })
124 }
125
126 pub fn is_red_up(&self) -> bool {
128 self.helper.borrow().contains("red_up")
129 }
130
131 pub fn is_red_down(&self) -> bool {
133 self.helper.borrow().contains("red_down")
134 }
135
136 pub fn is_blue_up(&self) -> bool {
138 self.helper.borrow().contains("blue_up")
139 }
140
141 pub fn is_blue_down(&self) -> bool {
143 self.helper.borrow().contains("blue_down")
144 }
145
146 pub fn is_beacon(&self) -> bool {
148 self.helper.borrow().contains("beacon")
149 }
150
151 pub fn process(&self) -> Ev3Result<()> {
154 let buttons = self.sensor.get_value(self.channel)?;
155
156 let mut helper = self.helper.borrow_mut();
157
158 if helper.last_buttons != buttons {
159 helper.last_buttons = buttons;
160
161 helper.pressed_buttons.clear();
162
163 match buttons {
164 1 => {
165 helper.pressed_buttons.insert("red_up".to_owned());
166 }
167 2 => {
168 helper.pressed_buttons.insert("red_down".to_owned());
169 }
170 3 => {
171 helper.pressed_buttons.insert("blue_up".to_owned());
172 }
173 4 => {
174 helper.pressed_buttons.insert("blue_down".to_owned());
175 }
176 5 => {
177 helper.pressed_buttons.insert("red_up".to_owned());
178 helper.pressed_buttons.insert("blue_up".to_owned());
179 }
180 6 => {
181 helper.pressed_buttons.insert("red_up".to_owned());
182 helper.pressed_buttons.insert("blue_down".to_owned());
183 }
184 7 => {
185 helper.pressed_buttons.insert("red_down".to_owned());
186 helper.pressed_buttons.insert("blue_up".to_owned());
187 }
188 8 => {
189 helper.pressed_buttons.insert("red_down".to_owned());
190 helper.pressed_buttons.insert("blue_down".to_owned());
191 }
192 9 => {
193 helper.pressed_buttons.insert("beacon".to_owned());
194 }
195 10 => {
196 helper.pressed_buttons.insert("red_up".to_owned());
197 helper.pressed_buttons.insert("red_down".to_owned());
198 }
199 11 => {
200 helper.pressed_buttons.insert("blue_up".to_owned());
201 helper.pressed_buttons.insert("blue_down".to_owned());
202 }
203 _ => {}
204 }
205 }
206 Ok(())
207 }
208}
209
210#[derive(Debug, Clone)]
212pub struct BeaconSeeker {
213 sensor: InfraredSensor,
214 channel: u8,
215}
216
217impl BeaconSeeker {
218 pub fn new(sensor: InfraredSensor, channel: u8) -> Ev3Result<BeaconSeeker> {
220 sensor.set_mode_ir_seek()?;
221
222 Ok(BeaconSeeker {
223 sensor,
224 channel: u8::max(1, u8::min(4, channel)) - 1,
225 })
226 }
227
228 pub fn get_heading(&self) -> Ev3Result<i32> {
230 self.sensor.get_value(self.channel * 2)
231 }
232
233 pub fn get_distance(&self) -> Ev3Result<i32> {
236 self.sensor.get_value(self.channel * 2 + 1)
237 }
238
239 pub fn get_heading_and_distance(&self) -> Ev3Result<(i32, i32)> {
242 Ok((
243 self.sensor.get_value(self.channel * 2)?,
244 self.sensor.get_value(self.channel * 2 + 1)?,
245 ))
246 }
247}