Skip to content

Commit

Permalink
Add initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
michielp1807 committed Dec 13, 2024
1 parent 3db67f7 commit 3e7bf2a
Show file tree
Hide file tree
Showing 7 changed files with 418 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "pps-time"
version = "0.1.0"
edition = "2021"

[dependencies]
libc = "0.2.168"
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# PPS Time
A Rust interface for Pulse Per Second (PPS) devices, based on [RFC 2783](https://datatracker.ietf.org/doc/html/rfc2783). This crate is part of [Project Pendulum](https://github.com/pendulum-project), and is used in [ntpd-rs](https://github.com/pendulum-project/ntpd-rs).

The `pps.rs` contains bindings that were automatically generated by rust-bindgen:
```
bindgen /usr/include/linux/pps.h -o ./src/pps.rs --with-derive-default --raw-line '#![allow(dead_code, non_camel_case_types)]'
```
72 changes: 72 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::{
fs::File,
io::Error,
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};

// These constants rely on macros which bindgen does not export from pps.h
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, Error> {
Ok(PpsDevice(File::open(path)?))
}

/// Perform ioctl request and check result for possible errors
unsafe fn ioctl<T>(&self, request: c_ulong, value: &mut T) -> Result<(), Error> {
let result = libc::ioctl(self.0.as_raw_fd(), request, value);
if result != 0 {
return Err(Error::last_os_error());
}
Ok(())
}

/// Perform ioctl request with uninitialized data
unsafe fn ioctl_uninit<T>(&self, request: c_ulong) -> Result<T, Error> {
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, Error> {
unsafe { self.ioctl_uninit(PPS_GETPARAMS) }
}

pub fn set_params(&self, params: &mut pps_kparams) -> Result<(), Error> {
unsafe { self.ioctl(PPS_SETPARAMS, params) }
}

pub fn get_cap(&self) -> Result<c_uint, Error> {
unsafe { self.ioctl_uninit(PPS_GETCAP) }
}

pub fn fetch(&self, timeout: Option<pps_ktime>) -> Result<pps_fdata, Error> {
let timeout = timeout.unwrap_or(pps_ktime {
sec: 0,
nsec: 0,
flags: PPS_TIME_INVALID,
});

let mut data = pps_fdata {
info: Default::default(),
timeout,
};

unsafe { self.ioctl(PPS_FETCH, &mut data)? };

Ok(data)
}
}
48 changes: 48 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use pps_time::{pps, PpsDevice};
use std::path::PathBuf;

/// A simple PPS demo program
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
println!("Example usage:");
println!("$ sudo ./target/debug/pps-time /dev/pps0");
return;
}

let path = PathBuf::from(&args[1]); // path to PPS device

println!("Opening PPS device {}", path.display());
let pps = PpsDevice::new(path).expect("Could not open file!");

let capabilities = pps.get_cap().expect("Could not get capabilities!");
println!("Capabilities: {:#x}", capabilities);

let mut params = pps.get_params().expect("Could not get params!");
println!("{:?}", params);

// Turn on CAPTUREASSERT if available
if capabilities & pps::PPS_CAPTUREASSERT != 0 {
params.mode |= pps::PPS_CAPTUREASSERT as i32;
} else {
println!("Cannot CAPTUREASSERT");
}
// Turn on CAPTURECLEAR if available
if capabilities & pps::PPS_CAPTURECLEAR != 0 {
params.mode |= pps::PPS_CAPTURECLEAR as i32;
} else {
println!("Cannot CAPTURECLEAR");
}

pps.set_params(&mut params).expect("Could not set params!");

if capabilities & pps::PPS_CANWAIT == 0 {
println!("Cannot CANWAIT");
return;
}

loop {
let data = pps.fetch(None).expect("Could not fetch!");
println!("{:#?}", data);
}
}
Loading

0 comments on commit 3e7bf2a

Please sign in to comment.