aboutsummaryrefslogtreecommitdiff
path: root/src/hid.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hid.rs')
-rw-r--r--src/hid.rs46
1 files changed, 46 insertions, 0 deletions
diff --git a/src/hid.rs b/src/hid.rs
index da70d81..6b09e98 100644
--- a/src/hid.rs
+++ b/src/hid.rs
@@ -10,6 +10,7 @@ use std::fs;
use std::io;
use std::os::fd::AsRawFd;
use std::path::{Path, PathBuf};
+use std::time::{Duration, Instant};
/// beyerdynamic USB vendor ID.
pub const BEYERDYNAMIC_VID: u16 = 0x2e50;
@@ -198,6 +199,51 @@ impl Hidraw {
self.file.read(buf)
}
+ /// Wait up to `timeout` for one input report on the interrupt IN
+ /// endpoint. Returns `Ok(None)` if none arrived in time.
+ pub fn read_with_timeout(&mut self, timeout: Duration) -> io::Result<Option<Vec<u8>>> {
+ let deadline = Instant::now() + timeout;
+ loop {
+ let now = Instant::now();
+ if now >= deadline {
+ return Ok(None);
+ }
+ let mut set = unsafe { std::mem::zeroed::<libc::fd_set>() };
+ unsafe { libc::FD_ZERO(&mut set) };
+ unsafe { libc::FD_SET(self.file.as_raw_fd(), &mut set) };
+ let remaining = deadline.saturating_duration_since(now);
+ let mut tv = libc::timeval {
+ tv_sec: remaining.as_secs() as libc::time_t,
+ tv_usec: remaining.subsec_micros() as libc::suseconds_t,
+ };
+ let n = unsafe {
+ libc::select(
+ self.file.as_raw_fd() + 1,
+ &mut set,
+ std::ptr::null_mut(),
+ std::ptr::null_mut(),
+ &mut tv,
+ )
+ };
+ if n < 0 {
+ let err = io::Error::last_os_error();
+ if err.kind() == io::ErrorKind::Interrupted {
+ continue;
+ }
+ return Err(err);
+ }
+ if n == 0 {
+ return Ok(None);
+ }
+ let mut buf = [0u8; 256];
+ match self.read(&mut buf) {
+ Ok(len) => return Ok(Some(buf[..len].to_vec())),
+ Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ }
+ }
+ }
+
/// Write to the interrupt OUT endpoint.
pub fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
use std::io::Write;