diff options
Diffstat (limited to '')
-rw-r--r-- | src/rusbtmc.rs | 81 |
1 files changed, 75 insertions, 6 deletions
diff --git a/src/rusbtmc.rs b/src/rusbtmc.rs index 994ae31..124b9ff 100644 --- a/src/rusbtmc.rs +++ b/src/rusbtmc.rs @@ -80,6 +80,10 @@ pub enum Error { Request, #[error("device does not support the request type")] NotSupported, + #[error("decoding error (utf-8)")] + Decoding(#[from] std::string::FromUtf8Error), + #[error("not implemented")] + NotImplemented, } /// Get a list of connected instruments @@ -89,6 +93,7 @@ pub fn instruments() -> Result<Vec<Instrument<rusb::GlobalContext>>, Error> { Err(e) => return Err(Error::Rusb(e)), }; + let mut instruments = Vec::<Instrument<rusb::GlobalContext>>::new(); for dev in devices.iter() { @@ -103,16 +108,22 @@ pub fn instruments() -> Result<Vec<Instrument<rusb::GlobalContext>>, Error> { /// 'High level' Instrument wrapper around rusb::Device pub struct Instrument<C: rusb::UsbContext> { connected: bool, + // rusb objects pub device: rusb::Device<C>, pub handle: Option<rusb::DeviceHandle<C>>, + // usbtmc capabilites capabilities: Option<Capabilities>, + // for linux kernel has_kernel_driver: bool, + // addresses in the usb device config_num: Option<u8>, iface_num: Option<u8>, ep_bulk_in: Option<u8>, ep_bulk_out: Option<u8>, ep_interrupt_in: Option<u8>, + // btag number to keep track of packet parts btag: Wrapping<u8>, + // default timeout timeout: Duration, } @@ -161,6 +172,10 @@ impl<C: rusb::UsbContext> Instrument<C> { }) } + pub fn is_connected(&self) -> bool { + return self.connected; + } + /// Opens (searches for) the USBTMC interface of the device /// /// It loops through the available usb interfaces and uses the first that @@ -197,6 +212,7 @@ impl<C: rusb::UsbContext> Instrument<C> { // check if it is has USB488 if iface_desc.protocol_code() == USB488_BINTERFACE_PROTOCOL { // TODO + return Err(Error::NotImplemented); } self.config_num = Some(cfg_desc.number()); @@ -439,6 +455,7 @@ impl<C: rusb::UsbContext> Instrument<C> { Ok(capabilities) } + /// pub fn pulse(&mut self) -> Result<(), Error> { if !self.connected { return Err(Error::NotConnected); @@ -480,6 +497,11 @@ impl<C: rusb::UsbContext> Instrument<C> { Ok(()) } + /// Write a string to the instrument + pub fn write(&mut self, message: &str) -> Result<usize, Error> { + return self.write_raw(message.as_bytes()); + } + /// Write binary data to the instrument pub fn write_raw(&mut self, data: &[u8]) -> Result<usize, Error> { if !self.connected { @@ -512,8 +534,8 @@ impl<C: rusb::UsbContext> Instrument<C> { ); let mut packet: [u8; PACKET_SIZE] = [0; PACKET_SIZE]; - packet[..12].clone_from_slice(&header); - packet[13..].clone_from_slice(chunk); + packet[..HEADER_SIZE].clone_from_slice(&header); + packet[(HEADER_SIZE +1)..].clone_from_slice(chunk); sent_bytes += match handle.write_bulk(endpoint, &packet, self.timeout) { Ok(sent) => sent, @@ -533,8 +555,8 @@ impl<C: rusb::UsbContext> Instrument<C> { } // send remainder - let padding = (4 - (last_data.len() % 4)) % 4; - let last_data_size: usize = last_data.len() + padding; + let pad_size = (4 - (last_data.len() % 4)) % 4; + let last_data_size: usize = last_data.len() + pad_size; let header = make_bulk_header( MsgId::DeviceDependent, @@ -544,11 +566,29 @@ impl<C: rusb::UsbContext> Instrument<C> { true, ); - // TODO: pad and send last byte + let mut packet: [u8; PACKET_SIZE] = [0; PACKET_SIZE]; + packet[..HEADER_SIZE].clone_from_slice(&header); + for i in 0..last_data.len() { + packet[HEADER_SIZE + 1 + i] = last_data[i]; + } + + sent_bytes += match handle.write_bulk( + endpoint, + &packet[..(HEADER_SIZE + last_data_size)], + self.timeout + ) { + Ok(sent) => sent, + Err(e) => { + dbg!("failed to send chunk during bulk out"); + self.abort_bulk_out(); + return Err(Error::Rusb(e)); + } + }; Ok(sent_bytes) } + /// Abort a bulk-out operation fn abort_bulk_out(&mut self) -> Result<(), Error> { if !self.connected { return Err(Error::NotConnected); @@ -576,6 +616,20 @@ impl<C: rusb::UsbContext> Instrument<C> { Ok(()) } + + /// Read binary data from the device and decode into an utf-8 string + pub fn read(&mut self) -> Result<String, Error> { + let data = self.read_raw()?; + return match String::from_utf8(data) { + Ok(s) => Ok(s), + Err(e) => Err(Error::Decoding(e)), + }; + } + + /// Read binary data from the device + pub fn read_raw(&mut self) -> Result<Vec<u8>, Error> { + return Err(Error::NotImplemented); + } } /// helper function to create bulk headers @@ -610,7 +664,7 @@ fn make_bulk_header( ts_bytes[0], ts_bytes[1], ts_bytes[2], - ts_bytes[4], + ts_bytes[3], // whether this is the last chunk match is_last { true => 0x01, @@ -624,3 +678,18 @@ fn make_bulk_header( header } + +impl<C: rusb::UsbContext> std::fmt::Debug for Instrument<C> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + // TODO: complete + f.debug_struct("Instrument") + .field("connected", &self.connected) + .field("capabilities", &self.capabilities) + .field("has_kernel_driver", &self.has_kernel_driver) + .field("config_num", &self.config_num) + .field("iface_num", &self.iface_num) + .finish() + + } +} + |