1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use libusb;
use std::sync::Mutex;
use super::{Device, Devices, UsbConfig, UsbTimeout};
use super::{YUBIHSM2_BULK_IN_ENDPOINT, YUBIHSM2_BULK_OUT_ENDPOINT};
use command::MAX_MSG_SIZE;
use connector::{Connection, ConnectionError, ConnectionErrorKind::UsbError};
use uuid::Uuid;
pub struct UsbConnection {
handle: Mutex<libusb::DeviceHandle<'static>>,
device: Device,
timeout: UsbTimeout,
}
impl UsbConnection {
pub fn open(config: &UsbConfig) -> Result<Self, ConnectionError> {
Devices::open(config.serial, UsbTimeout::from_millis(config.timeout_ms))
}
pub(super) fn new(device: Device, timeout: UsbTimeout) -> Result<Self, ConnectionError> {
let handle = device.open_handle()?;
let connection = UsbConnection {
device,
timeout,
handle: Mutex::new(handle),
};
Ok(connection)
}
pub fn device(&self) -> &Device {
&self.device
}
}
impl Connection for UsbConnection {
fn send_message(&self, _uuid: Uuid, cmd: Vec<u8>) -> Result<Vec<u8>, ConnectionError> {
let mut handle = self.handle.lock().unwrap();
send_message(&mut handle, cmd.as_ref(), self.timeout)?;
recv_message(&mut handle, self.timeout)
}
}
impl Default for UsbConnection {
fn default() -> Self {
Devices::open(None, UsbTimeout::default()).unwrap()
}
}
fn send_message(
handle: &mut libusb::DeviceHandle,
data: &[u8],
timeout: UsbTimeout,
) -> Result<usize, ConnectionError> {
let nbytes = handle.write_bulk(YUBIHSM2_BULK_OUT_ENDPOINT, data, timeout.duration())?;
if data.len() == nbytes {
Ok(nbytes)
} else {
fail!(
UsbError,
"incomplete bulk transfer: {} of {} bytes",
nbytes,
data.len()
);
}
}
fn recv_message(
handle: &mut libusb::DeviceHandle,
timeout: UsbTimeout,
) -> Result<Vec<u8>, ConnectionError> {
let mut response = vec![0u8; MAX_MSG_SIZE];
let nbytes = handle.read_bulk(YUBIHSM2_BULK_IN_ENDPOINT, &mut response, timeout.duration())?;
response.truncate(nbytes);
Ok(response)
}