use std::time::Duration;
use std::{slice, thread};
use crate::config::Command;
use crate::error::ChallengeResponseError;
use crate::sec::crc16;
#[cfg(any(feature = "rusb", target_os = "windows"))]
pub type BackendType = rusb::RUSBBackend;
#[cfg(all(feature = "nusb", not(feature = "rusb"), not(target_os = "windows")))]
pub type BackendType = nusb::NUSBBackend;
pub const CHALLENGE_SIZE: usize = 64;
const VENDOR_ID: [u16; 3] = [
0x1050, 0x1D50, 0x20A0, ];
const PRODUCT_ID: [u16; 11] = [
0x0010, 0x0110, 0x0113, 0x0114, 0x0116, 0x0401, 0x0403, 0x0405, 0x0407, 0x60FC, 0x4211, ];
#[cfg(all(feature = "nusb", not(feature = "rusb"), not(target_os = "windows")))]
pub mod nusb;
#[cfg(any(feature = "rusb", target_os = "windows"))]
pub mod rusb;
pub(crate) const PAYLOAD_SIZE: usize = 64;
pub(crate) const RESPONSE_SIZE: usize = 36;
pub(crate) const STATUS_UPDATE_PAYLOAD_SIZE: usize = 8;
pub(crate) const HID_GET_REPORT: u8 = 0x01;
pub(crate) const HID_SET_REPORT: u8 = 0x09;
pub(crate) const REPORT_TYPE_FEATURE: u16 = 0x03;
pub(crate) const WRITE_RESET_PAYLOAD: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0x8f];
bitflags! {
pub struct Flags: u8 {
const SLOT_WRITE_FLAG = 0x80;
const RESP_PENDING_FLAG = 0x40;
}
}
#[repr(C)]
#[repr(packed)]
pub struct Frame {
pub payload: [u8; PAYLOAD_SIZE],
command: Command,
crc: u16,
filler: [u8; 3],
}
impl Frame {
pub fn new(payload: [u8; PAYLOAD_SIZE], command: Command) -> Self {
let mut f = Frame {
payload,
command,
crc: 0,
filler: [0; 3],
};
f.crc = crc16(&f.payload).to_le();
f
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Device {
pub name: Option<String>,
pub serial: Option<u32>,
pub product_id: u16,
pub vendor_id: u16,
pub bus_id: u8,
pub address_id: u8,
}
pub trait Backend<DeviceHandle, Interface> {
fn new() -> Result<Self, ChallengeResponseError>
where
Self: Sized;
fn open_device(
&mut self,
bus_id: u8,
address_id: u8,
) -> Result<(DeviceHandle, Vec<Interface>), ChallengeResponseError>;
fn close_device(
&self,
handle: DeviceHandle,
interfaces: Vec<Interface>,
) -> Result<(), ChallengeResponseError>;
fn read(&self, handle: &mut DeviceHandle, buf: &mut [u8]) -> Result<usize, ChallengeResponseError>;
fn raw_write(&self, handle: &mut DeviceHandle, packet: &[u8]) -> Result<(), ChallengeResponseError>;
fn find_device(&mut self) -> Result<Device, ChallengeResponseError>;
fn find_device_from_serial(&mut self, serial: u32) -> Result<Device, ChallengeResponseError>;
fn find_all_devices(&mut self) -> Result<Vec<Device>, ChallengeResponseError>;
fn write_frame(&self, handle: &mut DeviceHandle, frame: &Frame) -> Result<(), ChallengeResponseError> {
let mut data = unsafe { slice::from_raw_parts(frame as *const Frame as *const u8, 70) };
let mut seq = 0;
let mut buf = [0; 8];
while !data.is_empty() {
let (a, b) = data.split_at(7);
if seq == 0 || b.is_empty() || a.iter().any(|&x| x != 0) {
let mut packet = [0; 8];
(&mut packet[..7]).copy_from_slice(a);
packet[7] = Flags::SLOT_WRITE_FLAG.bits() + seq;
self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?;
self.raw_write(handle, &packet)?;
}
data = b;
seq += 1
}
Ok(())
}
fn wait<F: Fn(Flags) -> bool>(
&self,
handle: &mut DeviceHandle,
f: F,
buf: &mut [u8],
) -> Result<(), ChallengeResponseError> {
loop {
self.read(handle, buf)?;
let flags = Flags::from_bits_truncate(buf[7]);
if flags.contains(Flags::SLOT_WRITE_FLAG) || flags.is_empty() {
}
if f(flags) {
return Ok(());
}
thread::sleep(Duration::new(0, 1000000));
}
}
fn write_reset(&self, handle: &mut DeviceHandle) -> Result<(), ChallengeResponseError> {
self.raw_write(handle, &WRITE_RESET_PAYLOAD)?;
let mut buf = [0; 8];
self.wait(handle, |x| !x.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?;
Ok(())
}
fn read_response(
&self,
handle: &mut DeviceHandle,
response: &mut [u8],
) -> Result<usize, ChallengeResponseError> {
let mut r0 = 0;
self.wait(
handle,
|f| f.contains(Flags::RESP_PENDING_FLAG),
&mut response[..8],
)?;
r0 += 7;
loop {
if self.read(handle, &mut response[r0..r0 + 8])? < 8 {
break;
}
let flags = Flags::from_bits_truncate(response[r0 + 7]);
if flags.contains(Flags::RESP_PENDING_FLAG) {
let seq = response[r0 + 7] & 0b00011111;
if r0 > 0 && seq == 0 {
break;
}
} else {
break;
}
r0 += 7;
}
self.write_reset(handle)?;
Ok(r0)
}
fn read_serial_from_device(
&mut self,
device_bus_id: u8,
device_address: u8,
) -> Result<u32, ChallengeResponseError> {
let (mut handle, interfaces) = self.open_device(device_bus_id, device_address)?;
let challenge = [0; CHALLENGE_SIZE];
let command = Command::DeviceSerial;
let d = Frame::new(challenge, command); let mut buf = [0; STATUS_UPDATE_PAYLOAD_SIZE];
self.wait(&mut handle, |f| !f.contains(Flags::SLOT_WRITE_FLAG), &mut buf)?;
self.write_frame(&mut handle, &d)?;
let mut response = [0; RESPONSE_SIZE];
self.read_response(&mut handle, &mut response)?;
self.close_device(handle, interfaces)?;
if crc16(&response[..6]) != crate::sec::CRC_RESIDUAL_OK {
return Err(ChallengeResponseError::WrongCRC);
}
let serial = structure!("2I").unpack(response[..8].to_vec())?;
Ok(serial.0)
}
}