use core::convert::TryFrom;
use heapless::Vec;
use interchange::{Interchange, Requester};
use crate::{
constants::*,
types::packet::{
Chain, ChainedPacket as _, Command as PacketCommand, DataBlock, Error as PacketError,
ExtPacket, PacketWithData as _, RawPacket, XfrBlock,
},
};
use usb_device::class_prelude::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum State {
Idle,
Receiving,
Processing,
ReadyToSend,
Sending,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(dead_code, clippy::enum_variant_names)]
enum Error {
CmdAborted = 0xff,
IccMute = 0xfe,
XfrParityError = 0xfd,
CmdSlotBusy = 0xE0,
CommandNotSupported = 0x00,
}
pub struct Pipe<Bus, I, const N: usize>
where
Bus: 'static + UsbBus,
I: 'static + Interchange<REQUEST = Vec<u8, N>, RESPONSE = Vec<u8, N>>,
{
pub(crate) write: EndpointIn<'static, Bus>,
seq: u8,
state: State,
interchange: Requester<I>,
sent: usize,
outbox: Option<RawPacket>,
ext_packet: ExtPacket,
#[allow(dead_code)]
packet_len: usize,
receiving_long: bool,
long_packet_missing: usize,
in_chain: usize,
pub(crate) started_processing: bool,
atr: Vec<u8, 32>,
}
impl<Bus, I, const N: usize> Pipe<Bus, I, N>
where
Bus: 'static + UsbBus,
I: 'static + Interchange<REQUEST = Vec<u8, N>, RESPONSE = Vec<u8, N>>,
{
pub(crate) fn new(
write: EndpointIn<'static, Bus>,
request_pipe: Requester<I>,
card_issuers_data: Option<&[u8]>,
) -> Self {
Self {
write,
seq: 0,
state: State::Idle,
sent: 0,
outbox: None,
interchange: request_pipe,
ext_packet: Default::default(),
packet_len: 0,
receiving_long: false,
long_packet_missing: 0,
in_chain: 0,
started_processing: false,
atr: Self::construct_atr(card_issuers_data, false),
}
}
fn construct_atr(card_issuers_data: Option<&[u8]>, signal_t_equals_0: bool) -> Vec<u8, 32> {
assert!(card_issuers_data.map_or(true, |data| data.len() <= 13));
let k = card_issuers_data.map_or(0u8, |data| 2 + data.len() as u8);
let mut atr = Vec::new();
atr.push(0x3B).ok();
atr.push(0x80 | k).ok();
if signal_t_equals_0 {
atr.push(0x80).ok();
}
atr.push(0x01).ok();
if let Some(data) = card_issuers_data {
atr.push(0x80).ok();
atr.push(0x50 | data.len() as u8).ok();
atr.extend_from_slice(data).ok();
}
let mut checksum = 0;
for byte in atr.iter().skip(1) {
checksum ^= *byte;
}
atr.push(checksum).ok();
atr
}
pub fn busy(&self) -> bool {
self.outbox.is_some()
}
}
impl<Bus, I, const N: usize> Pipe<Bus, I, N>
where
Bus: 'static + UsbBus,
I: 'static + Interchange<REQUEST = Vec<u8, N>, RESPONSE = Vec<u8, N>>,
{
pub fn handle_packet(&mut self, packet: RawPacket) {
use crate::types::packet::RawPacketExt;
if !self.receiving_long {
if packet.len() < 10 {
panic!("unexpected short packet");
}
self.ext_packet.clear();
self.ext_packet.extend_from_slice(&packet).unwrap();
let pl = packet.packet_len();
if pl > 54 {
self.receiving_long = true;
self.in_chain = 1;
self.long_packet_missing = pl - 54;
self.packet_len = pl;
return;
} else {
}
} else {
self.ext_packet.extend_from_slice(&packet).ok();
self.in_chain += 1;
assert!(packet.len() <= self.long_packet_missing);
self.long_packet_missing -= packet.len();
if self.long_packet_missing > 0 {
return;
} else {
self.receiving_long = false;
}
}
match PacketCommand::try_from(self.ext_packet.clone()) {
Ok(command) => {
self.seq = command.seq();
match command {
PacketCommand::PowerOn(_command) => self.send_atr(),
PacketCommand::PowerOff(_command) => self.send_slot_status_ok(),
PacketCommand::GetSlotStatus(_command) => self.send_slot_status_ok(),
PacketCommand::XfrBlock(command) => self.handle_transfer(command),
PacketCommand::Abort(_command) => {
todo!();
}
PacketCommand::GetParameters(_command) => self.send_parameters(),
}
}
Err(PacketError::ShortPacket) => {
panic!("short packet!");
}
Err(PacketError::UnknownCommand(_p)) => {
info!("unknown command {:X?}", &_p);
self.seq = self.ext_packet[6];
self.send_slot_status_error(Error::CommandNotSupported);
}
}
}
#[inline(never)]
fn reset_interchange(&mut self) {
let message = Vec::new();
self.interchange.take_response();
self.interchange.request(&message).ok();
self.interchange.cancel().ok();
}
fn handle_transfer(&mut self, command: XfrBlock) {
match self.state {
State::Idle => {
match command.chain() {
Chain::BeginsAndEnds => {
info!("begins and ends");
self.reset_interchange();
let message = self.interchange.request_mut().unwrap();
message.clear();
message.extend_from_slice(command.data()).unwrap();
self.call_app();
self.state = State::Processing;
}
Chain::Begins => {
info!("begins");
self.reset_interchange();
let message = self.interchange.request_mut().unwrap();
message.clear();
message.extend_from_slice(command.data()).unwrap();
self.state = State::Receiving;
self.send_empty_datablock(Chain::ExpectingMore);
}
_ => panic!("unexpectedly in idle state"),
}
}
State::Receiving => match command.chain() {
Chain::Continues => {
info!("continues");
let message = self.interchange.request_mut().unwrap();
assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH);
message.extend_from_slice(command.data()).unwrap();
self.send_empty_datablock(Chain::ExpectingMore);
}
Chain::Ends => {
info!("ends");
let message = self.interchange.request_mut().unwrap();
assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH);
message.extend_from_slice(command.data()).unwrap();
self.call_app();
self.state = State::Processing;
}
_ => panic!("unexpectedly in receiving state"),
},
State::Processing => {
panic!(
"ccid pipe unexpectedly received command while in processing state: {:?}",
&command
);
}
State::ReadyToSend => {
panic!("unexpectedly in ready-to-send state")
}
State::Sending => match command.chain() {
Chain::ExpectingMore => {
self.prime_outbox();
}
_ => panic!("unexpectedly in receiving state"),
},
}
}
pub fn send_wait_extension(&mut self) -> bool {
if self.state == State::Processing {
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet[0] = 0x80;
packet[6] = self.seq;
packet[7] = 2 << 6;
packet[8] = 0x1;
self.send_packet_assuming_possible(packet);
true
} else {
false
}
}
pub fn did_started_processing(&mut self) -> bool {
if self.started_processing {
self.started_processing = false;
true
} else {
false
}
}
#[inline(never)]
fn call_app(&mut self) {
self.interchange
.send_request()
.expect("could not deposit command");
self.started_processing = true;
self.state = State::Processing;
}
#[inline(never)]
pub fn poll_app(&mut self) {
if let State::Processing = self.state {
if interchange::State::Responded == self.interchange.state() {
self.state = State::ReadyToSend;
self.sent = 0;
self.prime_outbox();
}
}
}
pub fn prime_outbox(&mut self) {
if self.state != State::ReadyToSend && self.state != State::Sending {
return;
}
if self.outbox.is_some() {
panic!();
}
let message: &mut Vec<u8, N> = unsafe { (*self.interchange.interchange.get()).rp_mut() };
let chunk_size = core::cmp::min(PACKET_SIZE - 10, message.len() - self.sent);
let chunk = &message[self.sent..][..chunk_size];
self.sent += chunk_size;
let more = self.sent < message.len();
let chain = match (self.state, more) {
(State::ReadyToSend, true) => {
self.state = State::Sending;
Chain::Begins
}
(State::ReadyToSend, false) => {
self.state = State::Idle;
Chain::BeginsAndEnds
}
(State::Sending, true) => Chain::Continues,
(State::Sending, false) => {
self.state = State::Idle;
Chain::Ends
}
_ => {
return;
}
};
let primed_packet = DataBlock::new(self.seq, chain, chunk);
self.outbox = Some(primed_packet.into());
self.maybe_send_packet();
}
fn send_empty_datablock(&mut self, chain: Chain) {
let packet = DataBlock::new(self.seq, chain, &[]).into();
self.send_packet_assuming_possible(packet);
}
fn send_slot_status_ok(&mut self) {
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet[0] = 0x81;
packet[6] = self.seq;
self.send_packet_assuming_possible(packet);
}
fn send_slot_status_error(&mut self, error: Error) {
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet[0] = 0x6c;
packet[6] = self.seq;
packet[7] = 1 << 6;
packet[8] = error as u8;
self.send_packet_assuming_possible(packet);
}
fn send_parameters(&mut self) {
let mut packet = RawPacket::new();
packet.resize_default(17).ok();
packet[0] = 0x82;
packet[1] = 7;
packet[6] = self.seq;
packet[9] = 1;
packet[10] = (0b0001 << 4) | (0b0001);
packet[11] = 0x10;
packet[13] = 0x15;
packet[15] = 0xfe;
self.send_packet_assuming_possible(packet);
}
fn send_atr(&mut self) {
let atr = self.atr.clone();
let packet = DataBlock::new(
self.seq,
Chain::BeginsAndEnds,
&atr,
);
self.send_packet_assuming_possible(packet.into());
}
fn send_packet_assuming_possible(&mut self, packet: RawPacket) {
if self.outbox.is_some() {
self.state = State::Idle;
info!("overwriting last session..");
}
self.outbox = Some(packet);
self.maybe_send_packet();
}
#[inline(never)]
pub fn maybe_send_packet(&mut self) {
if let Some(packet) = self.outbox.as_ref() {
let needs_zlp = packet.len() == PACKET_SIZE;
match self.write.write(packet) {
Ok(n) if n == packet.len() => {
if needs_zlp {
self.outbox = Some(RawPacket::new());
} else {
self.outbox = None;
}
}
Ok(_) => panic!("short write"),
Err(UsbError::WouldBlock) => {
info!("waiting to send");
}
Err(_) => panic!("unexpected send error"),
}
}
}
pub fn expect_abort(&mut self, slot: u8, _seq: u8) {
debug_assert!(slot == 0);
info!("ABORT expected for seq = {}", _seq);
todo!();
}
}