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
use std::cell::RefCell; use std::collections::HashMap; use std::fmt::{self, Debug}; use std::fs; use std::string::String; use crate::{utils::OrErr, Attribute, Ev3Error, Ev3Result, Port}; pub const ROOT_PATH: &str = "/sys/class/"; pub struct Driver { class_name: String, name: String, attributes: RefCell<HashMap<String, Attribute>>, } impl Driver { pub fn new(class_name: &str, name: &str) -> Driver { Driver { class_name: class_name.to_owned(), name: name.to_owned(), attributes: RefCell::new(HashMap::new()), } } pub fn find_name_by_port_and_driver( class_name: &str, port: &dyn Port, driver_name: &str, ) -> Ev3Result<String> { let port_address = port.address(); let paths = fs::read_dir(format!("{}{}", ROOT_PATH, class_name))?; for path in paths { let file_name = path?.file_name(); let name = file_name.to_str().or_err()?; let address = Attribute::new(class_name, name, "address")?; if address.get::<String>()?.contains(&port_address) { let driver = Attribute::new(class_name, name, "driver_name")?; if driver.get::<String>()? == driver_name { return Ok(name.to_owned()); } } } Err(Ev3Error::NotFound) } pub fn find_name_by_port(class_name: &str, port: &dyn Port) -> Ev3Result<String> { let port_address = port.address(); let paths = fs::read_dir(format!("{}{}", ROOT_PATH, class_name))?; for path in paths { let file_name = path?.file_name(); let name = file_name.to_str().or_err()?; let address = Attribute::new(class_name, name, "address")?; if address.get::<String>()?.contains(&port_address) { return Ok(name.to_owned()); } } Err(Ev3Error::NotFound) } pub fn find_name_by_driver(class_name: &str, driver_name: &str) -> Ev3Result<String> { let mut names = Driver::find_names_by_driver(class_name, driver_name)?; match names.len() { 0 => Err(Ev3Error::NotFound), 1 => Ok(names .pop() .expect("Name vector contains exactly one element")), _ => Err(Ev3Error::MultipleMatches), } } pub fn find_names_by_driver(class_name: &str, driver_name: &str) -> Ev3Result<Vec<String>> { let paths = fs::read_dir(format!("{}{}", ROOT_PATH, class_name))?; let mut found_names = Vec::new(); for path in paths { let file_name = path?.file_name(); let name = file_name.to_str().or_err()?; let driver = Attribute::new(class_name, name, "driver_name")?; if driver.get::<String>()? == driver_name { found_names.push(name.to_owned()); } } Ok(found_names) } pub fn get_attribute(&self, attribute_name: &str) -> Attribute { let mut attributes = self.attributes.borrow_mut(); if !attributes.contains_key(attribute_name) { if let Ok(v) = Attribute::new(self.class_name.as_ref(), self.name.as_ref(), attribute_name) { attributes.insert(attribute_name.to_owned(), v); }; }; attributes .get(attribute_name) .expect("Internal error in the attribute map") .clone() } } impl Clone for Driver { fn clone(&self) -> Self { Driver { class_name: self.class_name.clone(), name: self.name.clone(), attributes: RefCell::new(HashMap::new()), } } } impl Debug for Driver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "Driver {{ class_name: {}, name: {} }}", self.class_name, self.name ) } }