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