pub mod info {
pub use crate::info_event::*;
}
use std::cmp::Ordering;
use std::ffi::{CStr, CString};
use std::os::{raw::c_char, unix::prelude::AsRawFd};
use std::path::Path;
use std::ptr;
use std::str;
use std::time::Duration;
use super::{
Error, OperationType, Result, gpiod,
line::{self, Offset},
request,
};
#[derive(Debug, Eq, PartialEq)]
pub struct Chip {
chip: *mut gpiod::gpiod_chip,
}
unsafe impl Send for Chip {}
impl Chip {
pub fn open<P: AsRef<Path>>(path: &P) -> Result<Self> {
let path = path.as_ref().to_string_lossy() + "\0";
let chip = unsafe { gpiod::gpiod_chip_open(path.as_ptr() as *const c_char) };
if chip.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipOpen,
errno::errno(),
));
}
Ok(Self { chip })
}
pub fn info(&self) -> Result<Info> {
Info::new(self)
}
pub fn path(&self) -> Result<&str> {
let path = unsafe { gpiod::gpiod_chip_get_path(self.chip) };
unsafe { CStr::from_ptr(path) }
.to_str()
.map_err(Error::StringNotUtf8)
}
pub fn line_info(&self, offset: Offset) -> Result<line::Info> {
let info = unsafe { gpiod::gpiod_chip_get_line_info(self.chip, offset) };
if info.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipGetLineInfo,
errno::errno(),
));
}
Ok(unsafe { line::Info::from_raw(info) })
}
pub fn watch_line_info(&self, offset: Offset) -> Result<line::Info> {
let info = unsafe { gpiod::gpiod_chip_watch_line_info(self.chip, offset) };
if info.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipWatchLineInfo,
errno::errno(),
));
}
Ok(unsafe { line::Info::from_raw(info) })
}
pub fn unwatch(&self, offset: Offset) {
unsafe {
gpiod::gpiod_chip_unwatch_line_info(self.chip, offset);
}
}
pub fn wait_info_event(&self, timeout: Option<Duration>) -> Result<bool> {
let timeout = match timeout {
Some(x) => x.as_nanos() as i64,
None => -1,
};
let ret = unsafe { gpiod::gpiod_chip_wait_info_event(self.chip, timeout) };
match ret {
-1 => Err(Error::OperationFailed(
OperationType::ChipWaitInfoEvent,
errno::errno(),
)),
0 => Ok(false),
_ => Ok(true),
}
}
pub fn read_info_event(&self) -> Result<info::Event> {
let event = unsafe { gpiod::gpiod_chip_read_info_event(self.chip) };
if event.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipReadInfoEvent,
errno::errno(),
));
}
Ok(unsafe { info::Event::from_raw(event) })
}
pub fn line_offset_from_name(&self, name: &str) -> Result<Offset> {
let name = CString::new(name).map_err(|_| Error::InvalidString)?;
let ret = unsafe {
gpiod::gpiod_chip_get_line_offset_from_name(self.chip, name.as_ptr() as *const c_char)
};
if ret == -1 {
Err(Error::OperationFailed(
OperationType::ChipGetLineOffsetFromName,
errno::errno(),
))
} else {
Ok(ret as u32)
}
}
pub fn request_lines(
&self,
rconfig: Option<&request::Config>,
lconfig: &line::Config,
) -> Result<request::Request> {
let req_cfg = match rconfig {
Some(cfg) => cfg.config,
_ => ptr::null(),
} as *mut gpiod::gpiod_request_config;
let request =
unsafe { gpiod::gpiod_chip_request_lines(self.chip, req_cfg, lconfig.config) };
if request.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipRequestLines,
errno::errno(),
));
}
unsafe { request::Request::from_raw(request) }
}
}
impl Drop for Chip {
fn drop(&mut self) {
unsafe { gpiod::gpiod_chip_close(self.chip) }
}
}
impl AsRawFd for Chip {
fn as_raw_fd(&self) -> i32 {
unsafe { gpiod::gpiod_chip_get_fd(self.chip) }
}
}
#[derive(Debug, Eq)]
pub struct Info {
info: *mut gpiod::gpiod_chip_info,
}
impl Info {
fn new(chip: &Chip) -> Result<Self> {
let info = unsafe { gpiod::gpiod_chip_get_info(chip.chip) };
if info.is_null() {
return Err(Error::OperationFailed(
OperationType::ChipGetInfo,
errno::errno(),
));
}
Ok(Self { info })
}
pub fn name(&self) -> Result<&str> {
let name = unsafe { gpiod::gpiod_chip_info_get_name(self.info) };
unsafe { CStr::from_ptr(name) }
.to_str()
.map_err(Error::StringNotUtf8)
}
pub fn label(&self) -> Result<&str> {
let label = unsafe { gpiod::gpiod_chip_info_get_label(self.info) };
unsafe { CStr::from_ptr(label) }
.to_str()
.map_err(Error::StringNotUtf8)
}
pub fn num_lines(&self) -> usize {
unsafe { gpiod::gpiod_chip_info_get_num_lines(self.info) }
}
}
impl PartialEq for Info {
fn eq(&self, other: &Self) -> bool {
self.name().unwrap().eq(other.name().unwrap())
}
}
impl PartialOrd for Info {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let name = match self.name() {
Ok(name) => name,
_ => return None,
};
let other_name = match other.name() {
Ok(name) => name,
_ => return None,
};
name.partial_cmp(other_name)
}
}
impl Drop for Info {
fn drop(&mut self) {
unsafe { gpiod::gpiod_chip_info_free(self.info) }
}
}