diff options
Diffstat (limited to 'hid/src/handle.rs')
-rw-r--r-- | hid/src/handle.rs | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/hid/src/handle.rs b/hid/src/handle.rs new file mode 100644 index 0000000..280bdcf --- /dev/null +++ b/hid/src/handle.rs @@ -0,0 +1,226 @@ +use std::time::Duration; + +use libc::c_int; +use sys::*; +use error::{self, Error}; + +pub struct Handle { + ptr: *mut hid_device, +} + +impl Handle { + #[doc(hidden)] + pub unsafe fn new(ptr: *mut hid_device) -> Self { + Handle { + ptr: ptr, + } + } + + #[doc(hidden)] + pub unsafe fn as_ptr(&self) -> *const hid_device { + self.ptr as *const _ + } + + #[doc(hidden)] + pub unsafe fn as_mut_ptr(&mut self) -> *mut hid_device { + self.ptr + } +} + +impl Handle { + /// Set the handle in blocking or non-blocking mode. + pub fn blocking(&mut self, value: bool) -> error::Result<()> { + unsafe { + match hid_set_nonblocking(self.as_mut_ptr(), if value { 1 } else { 0 }) { + 0 => + Ok(()), + + _ => + Err(Error::General) + } + } + } + + /// The data accessor. + pub fn data(&mut self) -> Data { + unsafe { + Data::new(self) + } + } + + /// The feature accessor. + pub fn feature(&mut self) -> Feature { + unsafe { + Feature::new(self) + } + } +} + +/// The data accessor. +pub struct Data<'a> { + handle: &'a mut Handle, +} + +impl<'a> Data<'a> { + #[doc(hidden)] + pub unsafe fn new(handle: &mut Handle) -> Data { + Data { handle: handle } + } + + /// Write data to the device. + /// + /// The first byte must be the report ID. + pub fn write<T: AsRef<[u8]>>(&mut self, data: T) -> error::Result<usize> { + let data = data.as_ref(); + + unsafe { + match hid_write(self.handle.as_mut_ptr(), data.as_ptr(), data.len()) { + -1 => + Err(Error::Write), + + length => + Ok(length as usize) + } + } + } + + /// Write data to the device with the given report ID. + pub fn write_to<T: AsRef<[u8]>>(&mut self, id: u8, data: T) -> error::Result<usize> { + let data = data.as_ref(); + let mut buffer = Vec::with_capacity(data.len() + 1); + + buffer.push(id); + buffer.extend(data); + + self.write(&buffer) + } + + /// Read data from the device. + /// + /// If the device supports reports the first byte will contain the report ID. + /// + /// Returns the amount of read bytes or `None` if there was a timeout. + pub fn read<T: AsMut<[u8]>>(&mut self, mut data: T, timeout: Duration) -> error::Result<Option<usize>> { + let data = data.as_mut(); + let result = if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + unsafe { + hid_read(self.handle.as_mut_ptr(), data.as_mut_ptr(), data.len()) + } + } + else { + unsafe { + // Timeout is in milliseconds. + hid_read_timeout(self.handle.as_mut_ptr(), data.as_mut_ptr(), data.len(), + timeout.as_secs() as c_int * 1_000 + timeout.subsec_nanos() as c_int / 1_000_000) + } + }; + + match result { + -1 => + Err(Error::Read), + + 0 => + Ok(None), + + v => + Ok(Some(v as usize)) + } + } + + /// Read data from the device. + /// + /// Returns the report ID and the amount of read bytes or `None` if there was a timeout. + pub fn read_from<T: AsMut<[u8]>>(&mut self, mut data: T, timeout: Duration) -> error::Result<Option<(u8, usize)>> { + let mut data = data.as_mut(); + let mut buffer = Vec::with_capacity(data.len() + 1); + + match try!(self.read(&mut buffer, timeout)) { + None => { + Ok(None) + } + + Some(length) => { + data.clone_from_slice(&buffer[1..length]); + + Ok(Some((data[0], length - 1))) + } + } + } +} + +/// The feature accessor. +pub struct Feature<'a> { + handle: &'a mut Handle, +} + +impl<'a> Feature<'a> { + #[doc(hidden)] + pub unsafe fn new(handle: &mut Handle) -> Feature { + Feature { handle: handle } + } + + /// Send a feature request. + /// + /// The first byte must be the report ID. + pub fn send<T: AsRef<[u8]>>(&mut self, data: T) -> error::Result<usize> { + let data = data.as_ref(); + + unsafe { + match hid_send_feature_report(self.handle.as_mut_ptr(), data.as_ptr(), data.len()) { + -1 => + Err(Error::Write), + + length => + Ok(length as usize) + } + } + } + + /// Send a feature request to the given report ID. + pub fn send_to<T: AsRef<[u8]>>(&mut self, id: u8, data: T) -> error::Result<usize> { + let data = data.as_ref(); + let mut buffer = Vec::with_capacity(data.len() + 1); + + buffer.push(id); + buffer.extend(data); + + self.send(&buffer).map(|v| v - 1) + } + + /// Get a feature request. + /// + /// The first byte must be the report ID. + pub fn get<T: AsMut<[u8]>>(&mut self, mut data: T) -> error::Result<Option<usize>> { + let data = data.as_mut(); + + unsafe { + match hid_get_feature_report(self.handle.as_mut_ptr(), data.as_mut_ptr(), data.len()) { + -1 => + Err(Error::Read), + + 0 => + Ok(None), + + v => + Ok(Some(v as usize)) + } + } + } + + /// Get a feature request from the given report ID. + pub fn get_from<T: AsMut<[u8]>>(&mut self, id: u8, mut data: T) -> error::Result<Option<usize>> { + let data = data.as_mut(); + let mut buffer = vec![0u8; data.len() + 1]; + + buffer[0] = id; + self.get(&mut buffer) + } +} + +impl Drop for Handle { + fn drop(&mut self) { + unsafe { + hid_close(self.as_mut_ptr()); + } + } +} |