ev3dev_lang_rust/
driver.rs1use std::cell::RefCell;
5use std::collections::HashMap;
6use std::fmt::{self, Debug};
7use std::fs;
8use std::path::Path;
9use std::string::String;
10
11use crate::utils::OrErr;
12use crate::{Attribute, Ev3Error, Ev3Result, Port};
13
14#[cfg(not(feature = "override-driver-path"))]
16pub const DRIVER_PATH: &str = "/sys/class/";
17
18#[cfg(feature = "override-driver-path")]
20pub const DRIVER_PATH: &str = get_driver_path();
21
22#[cfg(feature = "override-driver-path")]
23const fn get_driver_path() -> &'static str {
24 let path = std::option_env!("EV3DEV_DRIVER_PATH");
25 if let Some(path) = path {
26 path
27 } else {
28 "/sys/class/"
29 }
30}
31
32#[derive(Clone)]
35pub struct Driver {
36 class_name: String,
37 name: String,
38 attributes: RefCell<HashMap<String, Attribute>>,
39}
40
41impl Driver {
42 pub fn new(class_name: &str, name: &str) -> Driver {
45 Driver {
46 class_name: class_name.to_owned(),
47 name: name.to_owned(),
48 attributes: RefCell::new(HashMap::new()),
49 }
50 }
51
52 pub fn find_name_by_port_and_driver(
56 class_name: &str,
57 port: &dyn Port,
58 driver_name_vec: &[&str],
59 ) -> Ev3Result<String> {
60 let port_address = port.address();
61
62 let paths = fs::read_dir(Path::new(DRIVER_PATH).join(class_name))?;
63
64 for path in paths {
65 let file_name = path?.file_name();
66 let name = file_name.to_str().or_err()?;
67
68 let address = Attribute::from_sys_class(class_name, name, "address")?;
69
70 if address.get::<String>()?.contains(&port_address) {
71 let driver = Attribute::from_sys_class(class_name, name, "driver_name")?;
72 let driver_name = driver.get::<String>()?;
73 if driver_name_vec.iter().any(|n| &driver_name == n) {
74 return Ok(name.to_owned());
75 }
76 }
77 }
78
79 Err(Ev3Error::NotConnected {
80 device: format!("{driver_name_vec:?}"),
81 port: Some(port_address),
82 })
83 }
84
85 pub fn find_name_by_driver(class_name: &str, driver_name_vec: &[&str]) -> Ev3Result<String> {
90 let mut names = Driver::find_names_by_driver(class_name, driver_name_vec)?;
91
92 match names.len() {
93 0 => Err(Ev3Error::NotConnected {
94 device: format!("{driver_name_vec:?}"),
95 port: None,
96 }),
97 1 => Ok(names
98 .pop()
99 .expect("Name vector should contains exactly one element")),
100 _ => Err(Ev3Error::MultipleMatches {
101 device: format!("{driver_name_vec:?}"),
102 ports: names,
103 }),
104 }
105 }
106
107 pub fn find_names_by_driver(
109 class_name: &str,
110 driver_name_vec: &[&str],
111 ) -> Ev3Result<Vec<String>> {
112 let paths = fs::read_dir(Path::new(DRIVER_PATH).join(class_name))?;
113
114 let mut found_names = Vec::new();
115 for path in paths {
116 let file_name = path?.file_name();
117 let name = file_name.to_str().or_err()?;
118
119 let driver = Attribute::from_sys_class(class_name, name, "driver_name")?;
120
121 let driver_name = driver.get::<String>()?;
122 if driver_name_vec.iter().any(|n| &driver_name == n) {
123 found_names.push(name.to_owned());
124 }
125 }
126
127 Ok(found_names)
128 }
129
130 pub fn get_attribute(&self, attribute_name: &str) -> Attribute {
133 let mut attributes = self.attributes.borrow_mut();
134
135 if !attributes.contains_key(attribute_name) {
136 if let Ok(v) = Attribute::from_sys_class(
137 self.class_name.as_ref(),
138 self.name.as_ref(),
139 attribute_name,
140 ) {
141 attributes.insert(attribute_name.to_owned(), v);
142 };
143 };
144
145 attributes
146 .get(attribute_name)
147 .expect("Internal error in the attribute map")
148 .clone()
149 }
150}
151
152impl Debug for Driver {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(
155 f,
156 "Driver {{ class_name: {}, name: {} }}",
157 self.class_name, self.name
158 )
159 }
160}