use super::HidDevice;
use super::apdu::APDU;
use super::error::Error;
use super::to_arr;
use log;
use std::cmp::min;
use std::mem::size_of_val;
use std::slice;
pub const HID_RPT_SIZE: usize = 64;
pub const INIT_HEADER_SIZE: usize = 7;
const INIT_DATA_SIZE: usize = HID_RPT_SIZE - 12;
const CONT_DATA_SIZE: usize = HID_RPT_SIZE - 5;
pub const SW_NO_ERROR: [u8; 2] = [0x90, 0x00];
pub const SW_CONDITIONS_NOT_SATISFIED: [u8; 2] = [0x69, 0x85];
pub const SW_WRONG_DATA: [u8; 2] = [0x6A, 0x80];
pub const SW_WRONG_LENGTH: [u8; 2] = [0x67, 0x00];
pub const SW_INCORRECT_PARAMETERS: [u8; 2] = [0x6b, 0x00];
pub const SW_USER_CANCEL: [u8; 2] = [0x6A, 0x85];
fn get_hid_header(index: usize) -> [u8; 5] {
[0x01, 0x01, 0x05, (index >> 8) as u8, (index & 0xff) as u8]
}
fn check_recv_frame(frame: &[u8], index: usize) -> Result<(), Error> {
if size_of_val(frame) < 5 || frame[0] != 0x01 || frame[1] != 0x01 || frame[2] != 0x05 {
return Err(Error::CommError("Invalid frame header size".to_string()));
}
let seq = (frame[3] as usize) << 8 | (frame[4] as usize);
if seq != index {
return Err(Error::CommError("Invalid frame size".to_string()));
}
if index == 0 && size_of_val(frame) < 7 {
return Err(Error::CommError("Invalid frame size".to_string()));
}
Ok(())
}
fn get_init_header(apdu: &APDU) -> [u8; INIT_HEADER_SIZE] {
let mut buf = Vec::with_capacity(INIT_HEADER_SIZE);
buf.extend_from_slice(&[(apdu.len() >> 8) as u8, (apdu.len() & 0xff) as u8]);
buf.extend_from_slice(&apdu.raw_header());
to_arr(&buf)
}
fn set_data(data: &mut [u8], itr: &mut slice::Iter<u8>, max: usize) {
let available = itr.size_hint().0;
for i in 0..min(max, available) {
data[i] = *itr.next().unwrap();
}
}
fn sw_to_error(sw_h: u8, sw_l: u8) -> Result<(), Error> {
match [sw_l, sw_h] {
SW_NO_ERROR => Ok(()),
SW_WRONG_LENGTH => Err(Error::CommError("Incorrect length".to_string())),
SW_WRONG_DATA => Err(Error::CommError("Invalid data".to_string())),
SW_INCORRECT_PARAMETERS => Err(Error::CommError("Incorrect parameters".to_string())),
SW_USER_CANCEL => Err(Error::CommError("Canceled by user".to_string())),
SW_CONDITIONS_NOT_SATISFIED => Err(
Error::CommError("Conditions not satisfied()".to_string()),
),
v => Err(Error::CommError(
format!("Internal communication error: {:?}", v),
)),
}
}
pub fn sendrecv(dev: &HidDevice, apdu: &APDU) -> Result<Vec<u8>, Error> {
let mut frame_index: usize = 0;
let mut data_itr = apdu.data.iter();
let mut init_sent = false;
debug!(">> senrecv input: {:?}", &apdu);
while data_itr.size_hint().0 != 0 {
let mut frame: [u8; (HID_RPT_SIZE + 1) as usize] = [0; (HID_RPT_SIZE + 1) as usize];
&mut frame[1..6].clone_from_slice(&get_hid_header(frame_index));
if !init_sent {
frame[6..13].clone_from_slice(&get_init_header(&apdu));
init_sent = true;
set_data(&mut frame[13..], &mut data_itr, INIT_DATA_SIZE);
} else {
set_data(&mut frame[6..], &mut data_itr, CONT_DATA_SIZE);
}
if log_enabled!(log::LogLevel::Trace) {
let parts: Vec<String> = frame.iter().map(|byte| format!("{:02x}", byte)).collect();
trace!(">> USB send: {}", parts.join(""));
}
if let Err(err) = dev.write(&frame) {
return Err(err.into());
};
frame_index += 1;
}
debug!("\t |- read response");
frame_index = 0;
let mut data: Vec<u8> = Vec::new();
let datalen: usize;
let mut recvlen: usize = 0;
let mut frame: [u8; HID_RPT_SIZE] = [0u8; HID_RPT_SIZE];
let frame_size = dev.read(&mut frame)?;
check_recv_frame(&frame, frame_index)?;
datalen = (frame[5] as usize) << 8 | (frame[6] as usize);
data.extend_from_slice(&frame[7..frame_size]);
recvlen += frame_size;
frame_index += 1;
debug!(
"\t\t|-- init data: {:?}, recvlen: {}, datalen: {}",
data,
recvlen,
datalen
);
while recvlen < datalen {
frame = [0u8; HID_RPT_SIZE];
let frame_size = dev.read(&mut frame)?;
check_recv_frame(&frame, frame_index)?;
data.extend_from_slice(&frame[5..frame_size]);
recvlen += frame_size;
frame_index += 1;
debug!(
"\t\t|-- cont_{:?} size:{:?}, data: {:?}",
frame_index,
data.len(),
data
);
}
data.truncate(datalen);
match sw_to_error(data.pop().unwrap(), data.pop().unwrap()) {
Ok(_) => Ok(data),
Err(e) => Err(e),
}
}