use std::fmt;
use std::time::Duration;
use hid;
use super::super::AvailableDevice;
use crate::transport::error::Error;
use crate::transport::protocol::{Link, Protocol, ProtocolV1};
use crate::transport::{derive_model, AvailableDeviceTransport, ProtoMessage, Transport};
mod constants {
pub use super::super::constants::*;
pub const WIRELINK_USAGE: u16 = 0xFF00;
pub const WIRELINK_INTERFACE: isize = 0;
pub const DEBUGLINK_USAGE: u16 = 0xFF01;
pub const DEBUGLINK_INTERFACE: isize = 1;
}
const CHUNK_SIZE: usize = 64;
const READ_TIMEOUT_MS: u64 = 100000;
#[derive(Debug)]
enum HidVersion {
V1,
V2,
}
#[derive(Debug)]
pub struct AvailableHidTransport {
pub serial_nb: String,
}
impl fmt::Display for AvailableHidTransport {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "HID (serial nb: {})", &self.serial_nb)
}
}
pub struct HidLink {
hid_version: HidVersion,
_hid_manager: hid::Manager,
handle: Option<hid::Handle>,
}
impl Drop for HidLink {
fn drop(&mut self) {
self.handle.take();
}
}
impl Link for HidLink {
fn write_chunk(&mut self, chunk: Vec<u8>) -> Result<(), Error> {
debug_assert_eq!(CHUNK_SIZE, chunk.len());
let payload = match self.hid_version {
HidVersion::V1 => chunk,
HidVersion::V2 => {
let mut payload = vec![0];
payload.extend(chunk);
payload
}
};
self.handle.as_mut().unwrap().data().write(payload)?;
Ok(())
}
fn read_chunk(&mut self) -> Result<Vec<u8>, Error> {
let mut chunk = vec![0; 64];
match self
.handle
.as_mut()
.unwrap()
.data()
.read(&mut chunk, Duration::from_millis(READ_TIMEOUT_MS))?
{
Some(64) => Ok(chunk),
None => Err(Error::DeviceReadTimeout),
Some(chunk_size) => Err(Error::UnexpectedChunkSizeFromDevice(chunk_size)),
}
}
}
fn derive_debug(dev: &hid::Device) -> Option<bool> {
if dev.usage_page() == constants::DEBUGLINK_USAGE
|| dev.interface_number() == constants::DEBUGLINK_INTERFACE
{
Some(true)
} else if dev.usage_page() == constants::WIRELINK_USAGE
|| dev.interface_number() == constants::WIRELINK_INTERFACE
{
Some(false)
} else {
None
}
}
fn probe_hid_version(handle: &mut hid::Handle) -> Result<HidVersion, Error> {
let mut w = vec![0xff; 65];
w[0] = 0;
w[1] = 63;
if handle.data().write(w)? == 65 {
return Ok(HidVersion::V2);
}
let mut w = vec![0xff; 64];
w[0] = 63;
if handle.data().write(w)? == 64 {
return Ok(HidVersion::V1);
}
Err(Error::UnknownHidVersion)
}
pub struct HidTransport {
protocol: ProtocolV1<HidLink>,
}
impl HidTransport {
pub fn find_devices(debug: bool) -> Result<Vec<AvailableDevice>, Error> {
let hidman = hid::init()?;
let mut devices = Vec::new();
for dev in hidman.devices() {
let dev_id = (dev.vendor_id(), dev.product_id());
let model = match derive_model(dev_id) {
Some(m) => m,
None => continue,
};
if derive_debug(&dev) != Some(debug) {
continue;
}
let serial = match dev.serial_number() {
Some(s) => s.clone(),
None => continue,
};
devices.push(AvailableDevice {
model: model,
debug: debug,
transport: AvailableDeviceTransport::Hid(AvailableHidTransport {
serial_nb: serial,
}),
});
}
Ok(devices)
}
pub fn connect(device: &AvailableDevice) -> Result<Box<dyn Transport>, Error> {
let transport = match device.transport {
AvailableDeviceTransport::Hid(ref t) => t,
_ => panic!("passed wrong AvailableDevice in HidTransport::connect"),
};
let hidman = hid::init()?;
let mut handle = hidman
.devices()
.find_map(|dev| {
let dev_id = (dev.vendor_id(), dev.product_id());
if derive_model(dev_id) == Some(device.model.clone())
&& derive_debug(&dev) == Some(device.debug)
&& dev.serial_number() == Some(transport.serial_nb.clone())
{
Some(dev.open())
} else {
None
}
})
.ok_or(Error::DeviceNotFound)??;
let hid_version = probe_hid_version(&mut handle)?;
Ok(Box::new(HidTransport {
protocol: ProtocolV1 {
link: HidLink {
_hid_manager: hidman,
hid_version: hid_version,
handle: Some(handle),
},
},
}))
}
}
impl super::Transport for HidTransport {
fn session_begin(&mut self) -> Result<(), Error> {
self.protocol.session_begin()
}
fn session_end(&mut self) -> Result<(), Error> {
self.protocol.session_end()
}
fn write_message(&mut self, message: ProtoMessage) -> Result<(), Error> {
self.protocol.write(message)
}
fn read_message(&mut self) -> Result<ProtoMessage, Error> {
self.protocol.read()
}
}