use std::ops::Deref;
use std::str;
use std::time::Duration;
use std::{ffi::CStr, marker::PhantomData};
use super::{
Error, Result, gpiod,
line::{Bias, Direction, Drive, Edge, EventClock, Offset},
};
#[derive(Debug)]
#[repr(transparent)]
pub struct InfoRef {
_info: gpiod::gpiod_line_info,
_not_sync: PhantomData<*mut gpiod::gpiod_line_info>,
}
impl InfoRef {
pub(crate) unsafe fn from_raw<'a>(info: *mut gpiod::gpiod_line_info) -> &'a InfoRef {
unsafe { &*(info as *mut _) }
}
fn as_raw_ptr(&self) -> *mut gpiod::gpiod_line_info {
self as *const _ as *mut _
}
pub fn try_clone(&self) -> Result<Info> {
let copy = unsafe { gpiod::gpiod_line_info_copy(self.as_raw_ptr()) };
if copy.is_null() {
return Err(Error::OperationFailed(
crate::OperationType::LineInfoCopy,
errno::errno(),
));
}
Ok(unsafe { Info::from_raw(copy) })
}
pub fn offset(&self) -> Offset {
unsafe { gpiod::gpiod_line_info_get_offset(self.as_raw_ptr()) }
}
pub fn name(&self) -> Result<&str> {
let name = unsafe { gpiod::gpiod_line_info_get_name(self.as_raw_ptr()) };
if name.is_null() {
return Err(Error::NullString("GPIO line's name"));
}
unsafe { CStr::from_ptr(name) }
.to_str()
.map_err(Error::StringNotUtf8)
}
pub fn is_used(&self) -> bool {
unsafe { gpiod::gpiod_line_info_is_used(self.as_raw_ptr()) }
}
pub fn consumer(&self) -> Result<&str> {
let name = unsafe { gpiod::gpiod_line_info_get_consumer(self.as_raw_ptr()) };
if name.is_null() {
return Err(Error::NullString("GPIO line's consumer name"));
}
unsafe { CStr::from_ptr(name) }
.to_str()
.map_err(Error::StringNotUtf8)
}
pub fn direction(&self) -> Result<Direction> {
Direction::new(unsafe { gpiod::gpiod_line_info_get_direction(self.as_raw_ptr()) })
}
pub fn is_active_low(&self) -> bool {
unsafe { gpiod::gpiod_line_info_is_active_low(self.as_raw_ptr()) }
}
pub fn bias(&self) -> Result<Option<Bias>> {
Bias::new(unsafe { gpiod::gpiod_line_info_get_bias(self.as_raw_ptr()) })
}
pub fn drive(&self) -> Result<Drive> {
Drive::new(unsafe { gpiod::gpiod_line_info_get_drive(self.as_raw_ptr()) })
}
pub fn edge_detection(&self) -> Result<Option<Edge>> {
Edge::new(unsafe { gpiod::gpiod_line_info_get_edge_detection(self.as_raw_ptr()) })
}
pub fn event_clock(&self) -> Result<EventClock> {
EventClock::new(unsafe { gpiod::gpiod_line_info_get_event_clock(self.as_raw_ptr()) })
}
pub fn is_debounced(&self) -> bool {
unsafe { gpiod::gpiod_line_info_is_debounced(self.as_raw_ptr()) }
}
pub fn debounce_period(&self) -> Duration {
#[allow(clippy::unnecessary_cast)]
Duration::from_micros(unsafe {
gpiod::gpiod_line_info_get_debounce_period_us(self.as_raw_ptr()) as u64
})
}
}
#[derive(Debug)]
pub struct Info {
info: *mut gpiod::gpiod_line_info,
}
unsafe impl Send for Info {}
impl Info {
pub(crate) unsafe fn from_raw(info: *mut gpiod::gpiod_line_info) -> Info {
Info { info }
}
}
impl Deref for Info {
type Target = InfoRef;
fn deref(&self) -> &Self::Target {
unsafe { InfoRef::from_raw(self.info) }
}
}
impl Drop for Info {
fn drop(&mut self) {
unsafe { gpiod::gpiod_line_info_free(self.info) }
}
}