summaryrefslogtreecommitdiff
path: root/hid/src/handle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'hid/src/handle.rs')
-rw-r--r--hid/src/handle.rs226
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());
+ }
+ }
+}