diff --git a/sprinklers_linux/Cargo.toml b/sprinklers_linux/Cargo.toml new file mode 100644 index 0000000..2e34108 --- /dev/null +++ b/sprinklers_linux/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "sprinklers_linux" +version = "0.1.0" +authors = ["Alex Mikhalev "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sprinklers_core = { path = "../sprinklers_core" } +gpio-cdev = "0.4.0" +tracing = "0.1.21" +serde = { version = "1.0.116", features = ["derive"] } +eyre = "0.6.0" diff --git a/sprinklers_linux/src/lib.rs b/sprinklers_linux/src/lib.rs new file mode 100644 index 0000000..0ac0d1f --- /dev/null +++ b/sprinklers_linux/src/lib.rs @@ -0,0 +1,75 @@ +use sprinklers_core::section_interface::{SecId, SectionInterface}; + +use eyre::WrapErr; +use gpio_cdev::{LineHandle, LineRequestFlags}; +use serde::{Deserialize, Serialize}; +use tracing::{error, trace, warn}; + +pub struct LinuxGpio { + lines: Vec, +} + +impl SectionInterface for LinuxGpio { + fn num_sections(&self) -> SecId { + self.lines.len() as SecId + } + + fn set_section_state(&self, id: SecId, running: bool) { + if let Some(line) = &self.lines.get(id as usize) { + trace!( + line = line.line().offset(), + id, + running, + "setting state of line" + ); + if let Err(err) = line.set_value(running as u8) { + error!("error setting GPIO line value: {}", err); + } + } else { + warn!("set_section_state: invalid section id: {}", id); + } + } + + fn get_section_state(&self, id: SecId) -> bool { + if let Some(line) = &self.lines.get(id as usize) { + match line.get_value() { + Ok(active) => active != 0, + Err(err) => { + error!("error getting GPIO line value: {}", err); + false + } + } + } else { + warn!("get_section_state: invalid section id: {}", id); + false + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct LinuxGpioConfig { + chip_path: String, + line_offsets: Vec, +} + +impl LinuxGpioConfig { + pub fn build(self) -> eyre::Result { + let mut chip = + gpio_cdev::Chip::new(self.chip_path).wrap_err("could not create gpio_cdev Chip")?; + let lines: Result, eyre::Report> = self + .line_offsets + .into_iter() + .map(|line_offset| { + let line = chip + .get_line(line_offset) + .wrap_err("could not get line for chip")?; + let line_handle = line + .request(LineRequestFlags::OUTPUT, 0, "sprinklers_rs") + .wrap_err("could not request line access")?; + Ok(line_handle) + }) + .collect(); + let lines = lines?; + Ok(LinuxGpio { lines }) + } +}