Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic implementation of FtdiDeviceHandler #8

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions examples/ftdi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use env_logger;
use std::any::Any;
use std::net::*;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use usbip::{
ftdi::FtdiDeviceHandler, Direction, EndpointAttributes, SetupPacket, UsbDevice, UsbEndpoint,
UsbInterface, UsbInterfaceHandler,
};

const FTDI_VID: u16 = 0x0403;
const FTDI_PID: u16 = 0x6011;

#[derive(Clone)]
pub struct PseudoFtdiHandler {
tx_buffer: Vec<u8>,
}

impl PseudoFtdiHandler {
pub fn new() -> Self {
Self { tx_buffer: vec![] }
}
}

// This implemention does not
impl UsbInterfaceHandler for PseudoFtdiHandler {
fn handle_urb(
&mut self,
_interface: &UsbInterface,
ep: UsbEndpoint,
_setup: SetupPacket,
req: &[u8],
) -> Result<Vec<u8>, std::io::Error> {
// interrupt
if ep.attributes == EndpointAttributes::Interrupt as u8 {
Ok(vec![])
}
// bulk
else if let Direction::Out = ep.direction() {
// write to device/file here...
println!("Write endpoint {:02x}: {:?}", ep.address, req);
Ok(vec![])
} else {
// Read from the device.
// The first two bytes are device status.
// These must always be present, otherwise the ftdi driver on the remote side will
// consume these bytes.
if self.tx_buffer.len() > 0 {
let mut ftdi_packet: Vec<u8> = vec![0x01, 0x00];
ftdi_packet.extend(&self.tx_buffer);
self.tx_buffer = vec![];
println!("Read endpoint {:02x}: {:?}", ep.address, ftdi_packet);
Ok(ftdi_packet)
} else {
Ok(vec![0x01, 0x00])
}
}
}

fn get_class_specific_descriptor(&self) -> Vec<u8> {
vec![]
}

fn as_any(&mut self) -> &mut dyn Any {
self
}
}

fn ftdi_device() -> (
UsbDevice,
Arc<std::sync::Mutex<Box<dyn UsbInterfaceHandler + Send>>>,
) {
let pseudo = Arc::new(Mutex::new(
Box::new(PseudoFtdiHandler::new()) as Box<dyn usbip::UsbInterfaceHandler + Send>
));
let device_handler = Arc::new(Mutex::new(
Box::new(FtdiDeviceHandler::new()) as Box<dyn usbip::UsbDeviceHandler + Send>
));
let endpoints = FtdiDeviceHandler::endpoints(4);
let mut device = UsbDevice::new(0)
.with_interface(255, 255, 255, "", endpoints[0..2].to_vec(), pseudo.clone())
.with_interface(255, 255, 255, "", endpoints[2..4].to_vec(), pseudo.clone())
.with_interface(255, 255, 255, "", endpoints[4..6].to_vec(), pseudo.clone())
.with_interface(255, 255, 255, "", endpoints[6..8].to_vec(), pseudo.clone())
.with_device_handler(device_handler);

device.product_id = FTDI_PID;
device.vendor_id = FTDI_VID;
(device, pseudo)
}

#[tokio::main]
async fn main() {
env_logger::init();
let (device, handler) = ftdi_device();
let server = usbip::UsbIpServer::new_simulated(vec![device]);
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240);
tokio::spawn(usbip::server(addr, server));

loop {
tokio::time::sleep(Duration::from_secs(1)).await;
let mut handler = handler.lock().unwrap();
if let Some(ftdi) = handler.as_any().downcast_mut::<PseudoFtdiHandler>() {
ftdi.tx_buffer.extend(b"hello\0");
}
}
}
62 changes: 45 additions & 17 deletions src/device.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
use super::*;
use rusb::Version as rusbVersion;

#[derive(Clone, Default)]
pub struct Version {
pub major: u8,
pub minor: u8,
pub patch: u8,
}

impl From<rusbVersion> for Version {
fn from(value: rusbVersion) -> Self {
Self {
major: value.major(),
minor: value.minor(),
patch: value.sub_minor(),
}
}
}

impl Into<rusbVersion> for Version {
fn into(self) -> rusbVersion {
rusbVersion(self.major, self.minor, self.patch)
}
}

/// Represent a USB device
#[derive(Clone, Default)]
Expand All @@ -10,14 +34,16 @@ pub struct UsbDevice {
pub speed: u32,
pub vendor_id: u16,
pub product_id: u16,
pub device_bcd: u16,
pub device_bcd: Version,
pub device_class: u8,
pub device_subclass: u8,
pub device_protocol: u8,
pub configuration_value: u8,
pub num_configurations: u8,
pub interfaces: Vec<UsbInterface>,
pub device_handler: Option<Arc<Mutex<Box<dyn UsbDeviceHandler + Send>>>>,
pub usb_version: Version,

pub(crate) ep0_in: UsbEndpoint,
pub(crate) ep0_out: UsbEndpoint,
// strings
Expand Down Expand Up @@ -130,7 +156,9 @@ impl UsbDevice {
socket.write_u32(self.speed).await?;
socket.write_u16(self.vendor_id).await?;
socket.write_u16(self.product_id).await?;
socket.write_u16(self.device_bcd).await?;
socket
.write_u16((self.device_bcd.major as u16) << 8 | self.device_bcd.minor as u16)
.await?;
socket.write_u8(self.device_class).await?;
socket.write_u8(self.device_subclass).await?;
socket.write_u8(self.device_protocol).await?;
Expand Down Expand Up @@ -198,18 +226,18 @@ impl UsbDevice {
let mut desc = vec![
0x12, // bLength
Device as u8, // bDescriptorType: Device
0x10,
0x02, // bcdUSB: USB 2.1
self.device_class, // bDeviceClass
self.device_subclass, // bDeviceSubClass
self.device_protocol, // bDeviceProtocol
self.usb_version.minor as u8,
self.usb_version.major as u8, // bcdUSB: USB 2.0
self.device_class, // bDeviceClass
self.device_subclass, // bDeviceSubClass
self.device_protocol, // bDeviceProtocol
self.ep0_in.max_packet_size as u8, // bMaxPacketSize0
self.vendor_id as u8, // idVendor
self.vendor_id as u8, // idVendor
(self.vendor_id >> 8) as u8,
self.product_id as u8, // idProduct
(self.product_id >> 8) as u8,
self.device_bcd as u8, // bcdDevice
(self.device_bcd >> 8) as u8,
self.device_bcd.minor as u8, // bcdDevice
self.device_bcd.major as u8,
self.string_manufacturer, // iManufacturer
self.string_product, // iProduct
self.string_serial, // iSerial
Expand Down Expand Up @@ -331,14 +359,14 @@ impl UsbDevice {
let mut desc = vec![
0x0A, // bLength
DeviceQualifier as u8, // bDescriptorType: Device Qualifier
0x10,
0x02, // bcdUSB USB 2.1
self.device_class, // bDeviceClass
self.device_subclass, // bDeviceSUbClass
self.device_protocol, // bDeviceProtocol
self.usb_version.minor as u8,
self.usb_version.major as u8,
self.device_class, // bDeviceClass
self.device_subclass, // bDeviceSUbClass
self.device_protocol, // bDeviceProtocol
self.ep0_in.max_packet_size as u8, // bMaxPacketSize0
self.num_configurations, // bNumConfigurations
0x00, // reserved
self.num_configurations, // bNumConfigurations
0x00, // reserved
];

// requested len too short: wLength < real length
Expand Down
117 changes: 117 additions & 0 deletions src/ftdi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use crate::{EndpointAttributes, SetupPacket, UsbDeviceHandler, UsbEndpoint};
use std::any::Any;

const FTDI_DEVICE_REQ_TYPE: u8 = 0xC0;
const FTDI_SIO_RESET: u8 = 0; /* Reset the port */
const FTDI_SIO_MODEM_CTRL: u8 = 1; /* Set the modem control register */
const FTDI_SIO_SET_FLOW_CTRL: u8 = 2; /* Set flow control register */
const FTDI_SIO_SET_BAUD_RATE: u8 = 3; /* Set baud rate */
const FTDI_SIO_SET_DATA: u8 = 4; /* Set the data characteristics ofthe port */
const FTDI_SIO_GET_MODEM_STATUS: u8 = 5; /* Retrieve current value of modem status register */
const FTDI_SIO_SET_EVENT_CHAR: u8 = 6; /* Set the event character */
const FTDI_SIO_SET_ERROR_CHAR: u8 = 7; /* Set the error character */
const FTDI_SIO_SET_LATENCY_TIMER: u8 = 9; /* Set the latency timer */
const FTDI_SIO_GET_LATENCY_TIMER: u8 = 0x0a; /* Get the latency timer */
const FTDI_SIO_SET_BITMODE: u8 = 0x0b; /* Set bitbang mode */
const FTDI_SIO_READ_PINS: u8 = 0x0c; /* Read immediate value of pins */
const FTDI_SIO_READ_EEPROM: u8 = 0x90; /* Read EEPROM */

const EP_MAX_PACKET_SIZE: u16 = 512;

#[derive(Debug)]
enum FTDISIORequestTypes {
Reset,
ModemCtrl,
SetFlowCtrl,
SetBaudRate,
SetData,
GetModemStatus,
SetEventChar,
SetErrorChar,
SetLatencyTimer,
GetLatencyTimer,
SetBitmode,
ReadPins,
ReadEEPROM,
Unknown,
}

impl From<u8> for FTDISIORequestTypes {
fn from(orig: u8) -> Self {
match orig {
FTDI_SIO_RESET => FTDISIORequestTypes::Reset,
FTDI_SIO_MODEM_CTRL => FTDISIORequestTypes::ModemCtrl,
FTDI_SIO_SET_FLOW_CTRL => FTDISIORequestTypes::SetFlowCtrl,
FTDI_SIO_SET_BAUD_RATE => FTDISIORequestTypes::SetBaudRate,
FTDI_SIO_SET_DATA => FTDISIORequestTypes::SetData,
FTDI_SIO_GET_MODEM_STATUS => FTDISIORequestTypes::GetModemStatus,
FTDI_SIO_SET_EVENT_CHAR => FTDISIORequestTypes::SetEventChar,
FTDI_SIO_SET_ERROR_CHAR => FTDISIORequestTypes::SetErrorChar,
FTDI_SIO_SET_LATENCY_TIMER => FTDISIORequestTypes::SetLatencyTimer,
FTDI_SIO_GET_LATENCY_TIMER => FTDISIORequestTypes::GetLatencyTimer,
FTDI_SIO_SET_BITMODE => FTDISIORequestTypes::SetBitmode,
FTDI_SIO_READ_PINS => FTDISIORequestTypes::ReadPins,
FTDI_SIO_READ_EEPROM => FTDISIORequestTypes::ReadEEPROM,
_ => FTDISIORequestTypes::Unknown,
}
}
}

#[derive(Clone)]
pub struct FtdiDeviceHandler {}

impl FtdiDeviceHandler {
pub fn new() -> Self {
Self {}
}

pub fn endpoints(interface_count: u8) -> Vec<UsbEndpoint> {
let mut ret_eps = vec![];

for i in 0..interface_count {
ret_eps.push(UsbEndpoint {
/// bEndpointAddress
address: 0x81 + (0x2 * i),
/// bmAttributes
attributes: EndpointAttributes::Bulk as u8,
/// wMaxPacketSize
max_packet_size: EP_MAX_PACKET_SIZE as u16,
/// bInterval
interval: 0,
});

ret_eps.push(UsbEndpoint {
/// bEndpointAddress
address: 0x2 + (0x2 * i),
/// bmAttributes
attributes: EndpointAttributes::Bulk as u8,
/// wMaxPacketSize
max_packet_size: EP_MAX_PACKET_SIZE as u16,
/// bInterval
interval: 0,
})
}
ret_eps
}
}

impl UsbDeviceHandler for FtdiDeviceHandler {
fn handle_urb(&mut self, setup: SetupPacket, _: &[u8]) -> Result<Vec<u8>, std::io::Error> {
match setup.request_type {
FTDI_DEVICE_REQ_TYPE => match setup.request.into() {
FTDISIORequestTypes::GetModemStatus => Ok(vec![0x00]),
// 1 ms
FTDISIORequestTypes::GetLatencyTimer => Ok(vec![0x01]),
request => {
println!("Unhandled: {:?}", request);
Ok(vec![])
}
},
_ => Ok(vec![]),
}
}

fn as_any(&mut self) -> &mut dyn Any {
self
}
}
2 changes: 1 addition & 1 deletion src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl UsbInterfaceHandler for UsbHostInterfaceHandler {
"To host device: ep={:?} setup={:?} req={:?}",
ep, setup, req
);
let mut buffer = [0u8; 1024];
let mut buffer = vec![0u8; ep.max_packet_size as usize];
let timeout = std::time::Duration::new(1, 0);
let handle = self.handle.lock().unwrap();
if ep.attributes == EndpointAttributes::Control as u8 {
Expand Down
Loading