use crate::Result;
use std::time::Duration;
pub trait Transport {
fn control_read(
&self,
request: u8,
value: u16,
index: u16,
buf: &mut [u8],
timeout: Duration,
) -> Result<usize>;
fn control_write(
&self,
request: u8,
value: u16,
index: u16,
data: &[u8],
timeout: Duration,
) -> Result<usize>;
fn interrupt_read(&self, endpoint: u8, buf: &mut [u8], timeout: Duration) -> Result<usize>;
fn name(&self) -> &str;
}
use rusb::{DeviceHandle, UsbContext};
pub struct UsbTransport<T: UsbContext> {
handle: DeviceHandle<T>,
}
impl<T: UsbContext> UsbTransport<T> {
pub fn new(handle: DeviceHandle<T>) -> Self {
Self { handle }
}
pub fn handle(&self) -> &DeviceHandle<T> {
&self.handle
}
}
impl<T: UsbContext> Transport for UsbTransport<T> {
fn control_read(
&self,
request: u8,
value: u16,
index: u16,
buf: &mut [u8],
timeout: Duration,
) -> Result<usize> {
const REQ_TYPE_VENDOR_IN: u8 = 0xC0;
self.handle
.read_control(REQ_TYPE_VENDOR_IN, request, value, index, buf, timeout)
.map_err(crate::SpectroError::Usb)
}
fn control_write(
&self,
request: u8,
value: u16,
index: u16,
data: &[u8],
timeout: Duration,
) -> Result<usize> {
const REQ_TYPE_VENDOR_OUT: u8 = 0x40;
self.handle
.write_control(REQ_TYPE_VENDOR_OUT, request, value, index, data, timeout)
.map_err(crate::SpectroError::Usb)
}
fn interrupt_read(&self, endpoint: u8, buf: &mut [u8], timeout: Duration) -> Result<usize> {
self.handle
.read_interrupt(endpoint, buf, timeout)
.map_err(crate::SpectroError::Usb)
}
fn name(&self) -> &str {
"USB"
}
}
#[cfg(test)]
pub mod mock {
use super::*;
use std::cell::RefCell;
use std::collections::VecDeque;
pub type ControlWriteEntry = (u8, u16, u16, Vec<u8>);
pub struct MockTransport {
pub control_read_responses: RefCell<VecDeque<Vec<u8>>>,
pub interrupt_read_responses: RefCell<VecDeque<Vec<u8>>>,
pub control_write_log: RefCell<Vec<ControlWriteEntry>>,
}
impl MockTransport {
pub fn new() -> Self {
Self {
control_read_responses: RefCell::new(VecDeque::new()),
interrupt_read_responses: RefCell::new(VecDeque::new()),
control_write_log: RefCell::new(Vec::new()),
}
}
pub fn queue_control_read(&self, data: Vec<u8>) {
self.control_read_responses.borrow_mut().push_back(data);
}
pub fn queue_interrupt_read(&self, data: Vec<u8>) {
self.interrupt_read_responses.borrow_mut().push_back(data);
}
}
impl Default for MockTransport {
fn default() -> Self {
Self::new()
}
}
impl Transport for MockTransport {
fn control_read(
&self,
_request: u8,
_value: u16,
_index: u16,
buf: &mut [u8],
_timeout: Duration,
) -> Result<usize> {
let response = self
.control_read_responses
.borrow_mut()
.pop_front()
.unwrap_or_default();
let len = response.len().min(buf.len());
buf[..len].copy_from_slice(&response[..len]);
Ok(len)
}
fn control_write(
&self,
request: u8,
value: u16,
index: u16,
data: &[u8],
_timeout: Duration,
) -> Result<usize> {
self.control_write_log
.borrow_mut()
.push((request, value, index, data.to_vec()));
Ok(data.len())
}
fn interrupt_read(
&self,
_endpoint: u8,
buf: &mut [u8],
_timeout: Duration,
) -> Result<usize> {
let response = self
.interrupt_read_responses
.borrow_mut()
.pop_front()
.unwrap_or_default();
let len = response.len().min(buf.len());
buf[..len].copy_from_slice(&response[..len]);
Ok(len)
}
fn name(&self) -> &str {
"Mock"
}
}
}