ev3dev_lang_rust/port.rs
1//! Collection of port utils
2
3use crate::{Driver, Ev3Error, Ev3Result};
4
5/// EV3 ports
6pub trait Port {
7 /// Returns the name of the port.
8 fn address(&self) -> String;
9
10 /// Get the port device for this port
11 /// # Examples
12 ///
13 /// ```no_run
14 /// use ev3dev_lang_rust::{Ev3Result, Port};
15 /// use ev3dev_lang_rust::sensors::{ColorSensor, SensorPort};
16 /// use std::thread;
17 /// use std::time::Duration;
18 ///
19 /// fn init_color_sensor(port: SensorPort) -> Ev3Result<ColorSensor> {
20 /// let lego_port = port.get_lego_port()?;
21 /// lego_port.set_mode("ev3-uart")?;
22 /// lego_port.set_device("lego-ev3-color")?;
23 ///
24 /// thread::sleep(Duration::from_millis(100));
25 ///
26 /// ColorSensor::get(port)
27 /// }
28 ///
29 /// # fn main() -> Ev3Result<()> {
30 /// let color_sensor = init_color_sensor(SensorPort::In1)?;
31 /// # Ok(())
32 /// # }
33 fn get_lego_port(&self) -> Ev3Result<LegoPort>;
34}
35
36/// Lego ports
37#[derive(Debug, Clone)]
38pub struct LegoPort {
39 driver: Driver,
40}
41
42impl LegoPort {
43 fn new(driver: Driver) -> Self {
44 Self { driver }
45 }
46
47 fn map_error(e: Ev3Error) -> Ev3Error {
48 match e {
49 e @ Ev3Error::InternalError { .. } => e,
50 Ev3Error::NotConnected { device: _, port } => Ev3Error::NotConnected {
51 device: "LegoPort".to_owned(),
52 port,
53 },
54 Ev3Error::MultipleMatches { device: _, ports } => Ev3Error::MultipleMatches {
55 device: "LegoPort".to_owned(),
56 ports,
57 },
58 }
59 }
60
61 fn driver_names() -> Vec<&'static str> {
62 vec![
63 "ev3-input-port",
64 "ev3-output-port",
65 "modbrick-in-port",
66 "modbrick-out-port",
67 ]
68 }
69
70 /// Try to get a `Self` on the given port. Returns `None` if port is not used or another device is connected.
71 /// Get the port device for this port
72 /// # Examples
73 ///
74 /// ```no_run
75 /// use ev3dev_lang_rust::{Ev3Result, LegoPort};
76 /// use ev3dev_lang_rust::sensors::{ColorSensor, SensorPort};
77 /// use std::thread;
78 /// use std::time::Duration;
79 ///
80 /// fn init_color_sensor(port: SensorPort) -> Ev3Result<ColorSensor> {
81 /// let lego_port = LegoPort::get(port)?;
82 /// lego_port.set_mode("ev3-uart")?;
83 /// lego_port.set_device("lego-ev3-color")?;
84 ///
85 /// thread::sleep(Duration::from_millis(100));
86 ///
87 /// ColorSensor::get(port)
88 /// }
89 ///
90 /// # fn main() -> Ev3Result<()> {
91 /// let color_sensor = init_color_sensor(SensorPort::In1)?;
92 /// # Ok(())
93 /// # }
94 pub fn get<T: Port>(port: T) -> Ev3Result<Self> {
95 let driver_name_vec = Self::driver_names();
96
97 let name = Driver::find_name_by_port_and_driver("lego-port", &port, &driver_name_vec)
98 .map_err(Self::map_error)?;
99
100 Ok(Self::new(Driver::new("lego-port", &name)))
101 }
102
103 /// Try to find a `Self`. Only returns a device if their is exactly one connected, `Error::NotFound` otherwise.
104 pub fn find() -> Ev3Result<Self> {
105 let driver_name_vec = Self::driver_names();
106
107 let name =
108 Driver::find_name_by_driver("lego-port", &driver_name_vec).map_err(Self::map_error)?;
109
110 Ok(Self::new(Driver::new("lego-port", &name)))
111 }
112
113 /// Extract list of connected 'Self'
114 pub fn list() -> Ev3Result<Vec<Self>> {
115 let driver_name_vec = Self::driver_names();
116
117 Ok(Driver::find_names_by_driver("lego-port", &driver_name_vec)?
118 .iter()
119 .map(|name| Self::new(Driver::new("lego-port", name)))
120 .collect())
121 }
122
123 /// Returns the name of the port that the device is connected to.
124 pub fn get_address(&self) -> Ev3Result<String> {
125 self.driver.get_attribute("address").get()
126 }
127
128 /// Returns the name of the driver that provides this device.
129 pub fn get_driver_name(&self) -> Ev3Result<String> {
130 self.driver.get_attribute("driver_name").get()
131 }
132
133 /// Returns the currently selected mode.
134 pub fn get_mode(&self) -> Ev3Result<String> {
135 self.driver.get_attribute("mode").get()
136 }
137
138 /// Sets the currently selected mode.
139 /// Generally speaking when the mode changes any sensor or motor devices
140 /// associated with the port will be removed new ones loaded, however this
141 /// this will depend on the individual driver implementing this class.
142 pub fn set_mode(&self, mode: &str) -> Ev3Result<()> {
143 self.driver.get_attribute("mode").set_str_slice(mode)
144 }
145
146 /// Returns a list of the available modes of the port.
147 pub fn get_modes(&self) -> Ev3Result<Vec<String>> {
148 self.driver.get_attribute("modes").get_vec()
149 }
150
151 /// For modes that support it, writing the name of a driver will cause a new
152 /// device to be registered for that driver and attached to this port. For
153 /// example, since NXT/Analog sensors cannot be auto-detected, you must use
154 /// this attribute to load the correct driver. Returns -EOPNOTSUPP if setting a
155 /// device is not supported.
156 pub fn set_device(&self, mode: &str) -> Ev3Result<()> {
157 self.driver.get_attribute("set_device").set_str_slice(mode)
158 }
159
160 /// In most cases, reading status will return the same value as `mode`. In
161 /// cases where there is an `auto` mode additional values may be returned,
162 /// such as `no-device` or `error`. See individual port driver documentation
163 /// for the full list of possible values.
164 pub fn get_status(&self) -> Ev3Result<String> {
165 self.driver.get_attribute("status").get()
166 }
167}