1- //! A wrapper to a attribute file in the `/sys/class/` directory.
1+ //! A wrapper to a attribute file commonly in the `/sys/class/` directory.
22use std:: error:: Error ;
33use std:: fs:: { self , File , OpenOptions } ;
44use std:: io:: { Read , Seek , SeekFrom , Write } ;
@@ -7,7 +7,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
77use std:: string:: String ;
88use std:: sync:: { Arc , Mutex } ;
99
10- use crate :: { Ev3Error , Ev3Result } ;
10+ use crate :: { utils :: OrErr , Ev3Error , Ev3Result } ;
1111
1212/// The root driver path `/sys/class/`.
1313const ROOT_PATH : & str = "/sys/class/" ;
@@ -19,28 +19,98 @@ pub struct Attribute {
1919}
2020
2121impl Attribute {
22- /// Create a new `Attribute` instance that wrappes
23- /// the file `/sys/class/{class_name}/{name}{attribute_name}`.
24- pub fn new ( class_name : & str , name : & str , attribute_name : & str ) -> Ev3Result < Attribute > {
25- let filename = format ! ( "{}{}/{}/{}" , ROOT_PATH , class_name, name, attribute_name) ;
26-
27- let stat = fs:: metadata ( & filename) ?;
22+ /// Create a new `Attribute` instance for the given path.
23+ pub fn from_path ( path : & str ) -> Ev3Result < Attribute > {
24+ let stat = fs:: metadata ( & path) ?;
2825
2926 let mode = stat. permissions ( ) . mode ( ) ;
3027
31- let readable = mode & 256 == 256 ;
32- let writeable = mode & 128 == 128 ;
28+ // Read permission for group (`ev3dev`)
29+ let readable = mode & 0o040 == 0o040 ;
30+ let writeable = mode & 0o020 == 0o020 ;
3331
3432 let file = OpenOptions :: new ( )
3533 . read ( readable)
3634 . write ( writeable)
37- . open ( & filename ) ?;
35+ . open ( & path ) ?;
3836
3937 Ok ( Attribute {
4038 file : Arc :: new ( Mutex :: new ( file) ) ,
4139 } )
4240 }
4341
42+ /// Create a new `Attribute` instance that wrappes
43+ /// the file `/sys/class/{class_name}/{name}{attribute_name}`.
44+ pub fn from_sys_class (
45+ class_name : & str ,
46+ name : & str ,
47+ attribute_name : & str ,
48+ ) -> Ev3Result < Attribute > {
49+ let path = format ! ( "{}{}/{}/{}" , ROOT_PATH , class_name, name, attribute_name) ;
50+ Attribute :: from_path ( & path)
51+ }
52+
53+ /// Create a new `Attribute` instance by a discriminator attribute.
54+ /// This can be used to manually access driver files or advances features like raw encoder values.
55+ /// To find the correct file, this function iterates over all directories `$d` in `root_path` and
56+ /// checks if the content of `root_path/$d/discriminator_path` equals `discriminator_value`. When a
57+ /// match is found it returns an Attribute for file `root_path/$d/attribute_path`.
58+ ///
59+ /// # Example
60+ /// ```no_run
61+ /// use ev3dev_lang_rust::Attribute;
62+ ///
63+ /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
64+ /// // Get value0 of first connected color sensor.
65+ /// let color_sensor_value = Attribute::from_path_with_discriminator(
66+ /// "/sys/class/lego-sensor",
67+ /// "value0",
68+ /// "driver_name",
69+ /// "lego-ev3-color"
70+ /// )?;
71+ /// println!("value0 of color sensor: {}", color_sensor_value.get::<i32>()?);
72+ ///
73+ /// // Get raw rotation count of motor in port `A`.
74+ /// // See https://github.com/ev3dev/ev3dev/wiki/Internals:-ev3dev-stretch for more infomation.
75+ /// let rotation_count = Attribute::from_path_with_discriminator(
76+ /// "/sys/bus/iio/devices",
77+ /// "in_count0_raw",
78+ /// "name",
79+ /// "ev3-tacho"
80+ /// )?;
81+ /// println!("Raw rotation count: {}", rotation_count.get::<i32>()?);
82+ ///
83+ /// # Ok(())
84+ /// # }
85+ /// ```
86+ pub fn from_path_with_discriminator (
87+ root_path : & str ,
88+ attribute_path : & str ,
89+ discriminator_path : & str ,
90+ discriminator_value : & str ,
91+ ) -> Ev3Result < Attribute > {
92+ let paths = fs:: read_dir ( root_path) ?;
93+
94+ for path_result in paths {
95+ let path_buf = path_result?. path ( ) ;
96+ let current_path = path_buf. to_str ( ) . or_err ( ) ?;
97+
98+ let discriminator_attribute =
99+ Attribute :: from_path ( & format ! ( "{}/{}" , current_path, discriminator_path) ) ?;
100+
101+ if discriminator_attribute. get :: < String > ( ) ? == discriminator_value {
102+ return Attribute :: from_path ( & format ! ( "{}/{}" , current_path, attribute_path) ) ;
103+ }
104+ }
105+
106+ Err ( Ev3Error :: InternalError {
107+ msg : format ! (
108+ "Attribute `{}` at root path `{}` coult not be found!" ,
109+ attribute_path, root_path
110+ ) ,
111+ } )
112+ }
113+
44114 /// Returns the current value of the wrapped file.
45115 fn get_str ( & self ) -> Ev3Result < String > {
46116 let mut value = String :: new ( ) ;
0 commit comments