1#![crate_type = "lib"]
13#![crate_name = "sysfs_pwm"]
14
15use std::io::prelude::*;
18use std::os::unix::prelude::*;
19use std::fs::File;
20use std::fs;
21use std::fs::OpenOptions;
22use std::str::FromStr;
23
24mod error;
25pub use error::Error;
26
27#[derive(Debug)]
28pub struct PwmChip {
29 pub number: u32,
30}
31
32#[derive(Debug)]
33pub struct Pwm {
34 chip: PwmChip,
35 number: u32,
36}
37
38#[derive(Debug)]
39pub enum Polarity {
40 Normal,
41 Inverse,
42}
43
44pub type Result<T> = ::std::result::Result<T, error::Error>;
45
46fn pwm_file_wo(chip: &PwmChip, pin: u32, name: &str) -> Result<File> {
48 let f = try!(OpenOptions::new().write(true)
49 .open(format!("/sys/class/pwm/pwmchip{}/pwm{}/{}",
50 chip.number,
51 pin,
52 name)));
53 Ok(f)
54}
55
56fn pwm_file_ro(chip: &PwmChip, pin: u32, name: &str) -> Result<File> {
58 let f = try!(File::open(format!("/sys/class/pwm/pwmchip{}/pwm{}/{}", chip.number, pin, name)));
59 Ok(f)
60}
61
62fn pwm_file_parse<T: FromStr>(chip: &PwmChip, pin: u32, name: &str) -> Result<T> {
64 let mut s = String::with_capacity(10);
65 let mut f = try!(pwm_file_ro(chip, pin, name));
66 try!(f.read_to_string(&mut s));
67 match s.trim().parse::<T>() {
68 Ok(r) => Ok(r),
69 Err(_) => Err(Error::Unexpected(format!("Unexpeted value file contents: {:?}", s))),
70 }
71}
72
73
74impl PwmChip {
75 pub fn new(number: u32) -> Result<PwmChip> {
76 try!(fs::metadata(&format!("/sys/class/pwm/pwmchip{}", number)));
77 Ok(PwmChip { number: number })
78 }
79
80 pub fn count(&self) -> Result<u32> {
81 let npwm_path = format!("/sys/class/pwm/pwmchip{}/npwm", self.number);
82 let mut npwm_file = try!(File::open(&npwm_path));
83 let mut s = String::new();
84 try!(npwm_file.read_to_string(&mut s));
85 match s.parse::<u32>() {
86 Ok(n) => Ok(n),
87 Err(_) => Err(Error::Unexpected(format!("Unexpected npwm contents: {:?}", s))),
88 }
89 }
90
91 pub fn export(&self, number: u32) -> Result<()> {
92 if let Err(_) = fs::metadata(&format!("/sys/class/pwm/pwmchip{}/pwm{}",
94 self.number,
95 number)) {
96 let path = format!("/sys/class/pwm/pwmchip{}/export", self.number);
97 let mut export_file = try!(File::create(&path));
98 let _ = export_file.write_all(format!("{}", number).as_bytes());
99 }
100 Ok(())
101 }
102
103 pub fn unexport(&self, number: u32) -> Result<()> {
104 if let Ok(_) = fs::metadata(&format!("/sys/class/pwm/pwmchip{}/pwm{}",
105 self.number,
106 number)) {
107 let path = format!("/sys/class/pwm/pwmchip{}/unexport", self.number);
108 let mut export_file = try!(File::create(&path));
109 let _ = export_file.write_all(format!("{}", number).as_bytes());
110 }
111 Ok(())
112 }
113}
114
115impl Pwm {
116 pub fn new(chip: u32, number: u32) -> Result<Pwm> {
120 let chip: PwmChip = try!(PwmChip::new(chip));
121 Ok(Pwm {
122 chip: chip,
123 number: number,
124 })
125 }
126
127 #[inline]
129 pub fn with_exported<F>(&self, closure: F) -> Result<()>
130 where F: FnOnce() -> Result<()>
131 {
132 try!(self.export());
133 match closure() {
134 Ok(()) => self.unexport(),
135 Err(_) => self.unexport(),
136 }
137 }
138
139 pub fn export(&self) -> Result<()> {
141 self.chip.export(self.number)
142 }
143
144 pub fn unexport(&self) -> Result<()> {
146 self.chip.unexport(self.number)
147 }
148
149 pub fn enable(&self, enable: bool) -> Result<()> {
151 let mut enable_file = try!(pwm_file_wo(&self.chip, self.number, "enable"));
152 let contents = if enable {
153 "1"
154 } else {
155 "0"
156 };
157 try!(enable_file.write_all(contents.as_bytes()));
158 Ok(())
159 }
160
161 pub fn get_duty_cycle_ns(&self) -> Result<u32> {
163 pwm_file_parse::<u32>(&self.chip, self.number, "duty_cycle")
164 }
165
166 pub fn set_duty_cycle_ns(&self, duty_cycle_ns: u32) -> Result<()> {
170 let mut duty_cycle_file = try!(pwm_file_wo(&self.chip, self.number, "duty_cycle"));
172 try!(duty_cycle_file.write_all(format!("{}", duty_cycle_ns).as_bytes()));
173 Ok(())
174 }
175
176 pub fn get_period_ns(&self) -> Result<u32> {
178 pwm_file_parse::<u32>(&self.chip, self.number, "period")
179 }
180
181 pub fn set_period_ns(&self, period_ns: u32) -> Result<()> {
183 let mut period_file = try!(pwm_file_wo(&self.chip, self.number, "period"));
184 try!(period_file.write_all(format!("{}", period_ns).as_bytes()));
185 Ok(())
186 }
187}