1use anyhow::{bail, Context};
2use ev3dev_lang_rust::motors::TachoMotor;
3use ev3dev_lang_rust::sensors::SensorPort;
4
5use crate::error::Result;
6use crate::input::Input;
7use crate::movement::spec::RobotSpec;
8use crate::types::{Distance, Heading, Percent, Speed};
9use std::cell::RefMut;
10use std::time::Duration;
11
12#[derive(Eq, PartialEq, Copy, Clone, Debug)]
14pub enum TurnType {
15 Right,
17
18 Left,
20
21 Center,
23}
24
25impl TurnType {
26 pub fn wheels(&self) -> (bool, bool) {
27 match self {
28 TurnType::Right => (false, true),
29 TurnType::Left => (true, false),
30 TurnType::Center => (true, true),
31 }
32 }
33}
34
35#[derive(Eq, PartialEq, Copy, Clone, Hash, Debug)]
37pub enum MotorId {
38 DriveRight,
39 DriveLeft,
40 Attachment1,
41 Attachment2,
42}
43#[derive(Clone, Debug, PartialEq)]
46pub enum Command {
47 On(Speed),
50
51 Stop(StopAction),
53
54 Distance(Distance, Speed),
57
58 To(Distance, Speed),
63
64 Time(Duration, Speed),
67
68 Queue(Box<Command>),
75
76 Execute,
78}
79
80#[derive(Copy, Clone, Debug, Eq, PartialEq)]
82pub enum StopAction {
83 Coast,
85 Break,
87 Hold,
89}
90
91impl StopAction {
92 pub fn to_str(&self) -> &'static str {
93 match self {
94 StopAction::Coast => TachoMotor::STOP_ACTION_COAST,
95 StopAction::Break => TachoMotor::STOP_ACTION_BRAKE,
96 StopAction::Hold => TachoMotor::STOP_ACTION_HOLD,
97 }
98 }
99}
100
101#[derive(Eq, PartialEq, Copy, Clone, Hash, Debug)]
103pub enum SensorId {
104 DriveLeft,
105 AttachmentRight,
106 AttachmentLeft,
107}
108
109pub trait Robot: AngleProvider {
111 fn drive(&self, distance: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()>;
119
120 fn turn(&self, angle: Heading, speed: impl Into<Speed>) -> Result<()>;
136
137 fn turn_named(&self, angle: Heading, speed: impl Into<Speed>, turn: TurnType) -> Result<()>;
153
154 fn set_heading(&self, angle: Heading) -> Result<()>;
155
156 fn motor(&self, motor: MotorId) -> Option<RefMut<dyn Motor>>;
158
159 fn color_sensor(&self, port: SensorPort) -> Option<RefMut<dyn ColorSensor>>;
160
161 fn process_buttons(&self) -> Result<Input>;
163
164 fn handle_interrupt(&self) -> Result<()> {
167 let input = self.process_buttons().context("Process buttons")?;
168
169 if input.is_left() {
170 bail!("Interupt requested")
171 }
172
173 Ok(())
174 }
175
176 fn battery(&self) -> Result<Percent>;
179
180 fn await_input(&self, timeout: Option<Duration>) -> Result<Input>;
182
183 fn stop(&self) -> Result<()>;
185
186 fn reset(&self) -> Result<()>;
188
189 fn spec(&self) -> &RobotSpec;
191}
192
193pub trait ColorSensor {
194 fn reflected_light(&self) -> Result<Percent>;
196
197 fn cal_white(&mut self) -> Result<()>;
199
200 fn cal_black(&mut self) -> Result<()>;
202
203 fn reset(&mut self) -> Result<()>;
205}
206
207pub trait Motor {
208 fn raw(&mut self, command: Command) -> Result<()>;
210
211 fn motor_reset(&mut self, stop_action: Option<StopAction>) -> Result<()>;
214
215 fn wait(&self, timeout: Option<Duration>) -> Result<()>;
217
218 fn speed(&self) -> Result<Speed>;
220
221 fn motor_angle(&self) -> Result<Distance>;
223}
224
225pub trait MotorExt {
226 fn dist(&mut self, dist: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()>;
228
229 fn to_pos(&mut self, position: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()>;
233
234 fn time(&mut self, duration: Duration, speed: impl Into<Speed>) -> Result<()>;
236}
237
238impl MotorExt for dyn Motor + '_ {
239 fn dist(&mut self, dist: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()> {
240 self.raw(Command::Distance(dist.into(), speed.into()))?;
241
242 self.wait(None)
243 }
244
245 fn to_pos(&mut self, position: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()> {
246 self.raw(Command::To(position.into(), speed.into()))?;
247
248 self.wait(None)
249 }
250
251 fn time(&mut self, duration: Duration, speed: impl Into<Speed>) -> Result<()> {
252 self.raw(Command::Time(duration, speed.into()))?;
253
254 self.wait(None)
255 }
256}
257
258impl<M: Motor> MotorExt for M {
259 fn dist(&mut self, dist: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()> {
260 self.raw(Command::Distance(dist.into(), speed.into()))?;
261
262 self.wait(None)
263 }
264
265 fn to_pos(&mut self, position: impl Into<Distance>, speed: impl Into<Speed>) -> Result<()> {
266 self.raw(Command::To(position.into(), speed.into()))?;
267
268 self.wait(None)
269 }
270
271 fn time(&mut self, duration: Duration, speed: impl Into<Speed>) -> Result<()> {
272 self.raw(Command::Time(duration, speed.into()))?;
273
274 self.wait(None)
275 }
276}
277
278pub trait AngleProvider {
279 fn angle(&self) -> Result<Heading>;
281}