use std::{
fs::File,
io::{Error, Result},
mem::MaybeUninit,
os::{
fd::AsRawFd,
raw::{c_uint, c_ulong},
},
path::PathBuf,
};
pub mod pps;
use pps::{pps_fdata, pps_kparams, pps_ktime, PPS_TIME_INVALID};
const PPS_GETPARAMS: c_ulong = 0x800870a1;
const PPS_SETPARAMS: c_ulong = 0x400870a2;
const PPS_GETCAP: c_ulong = 0x800870a3;
const PPS_FETCH: c_ulong = 0xc00870a4;
pub struct PpsDevice(File);
impl PpsDevice {
pub fn new(path: PathBuf) -> Result<PpsDevice> {
Ok(PpsDevice(File::open(path)?))
}
unsafe fn ioctl<T>(&self, request: c_ulong, value: &mut T) -> Result<()> {
match libc::ioctl(self.0.as_raw_fd(), request as _, value) {
0 => Ok(()),
_ => Err(Error::last_os_error()),
}
}
unsafe fn ioctl_uninit<T>(&self, request: c_ulong) -> Result<T> {
let mut value: MaybeUninit<T> = MaybeUninit::uninit();
self.ioctl(request, &mut value)?;
Ok(unsafe { value.assume_init() })
}
pub fn get_params(&self) -> Result<pps_kparams> {
unsafe { self.ioctl_uninit(PPS_GETPARAMS) }
}
pub fn set_params(&self, params: &mut pps_kparams) -> Result<()> {
unsafe { self.ioctl(PPS_SETPARAMS, params) }
}
pub fn get_cap(&self) -> Result<c_uint> {
unsafe { self.ioctl_uninit(PPS_GETCAP) }
}
fn fetch(&self, timeout: pps_ktime) -> Result<pps_fdata> {
let mut data = pps_fdata {
info: Default::default(),
timeout,
};
unsafe { self.ioctl(PPS_FETCH, &mut data)? };
Ok(data)
}
pub fn fetch_blocking(&self) -> Result<pps_fdata> {
self.fetch(pps_ktime {
sec: 0,
nsec: 0,
flags: PPS_TIME_INVALID,
})
}
pub fn fetch_timeout(&self, seconds: i64, nanoseconds: i32) -> Result<pps_fdata> {
self.fetch(pps_ktime {
sec: seconds,
nsec: nanoseconds,
flags: 0,
})
}
pub fn fetch_non_blocking(&self) -> Result<pps_fdata> {
self.fetch(pps_ktime {
sec: 0,
nsec: 0,
flags: 0,
})
}
}