Teensy USB relaying

Status
Not open for further replies.

palesius

Member
I am attempting to put a device together to relay USB traffic for a USB device to a host, with the ability to view/inject/alter packets.
A particular use case I'm interested in is programtically sending button presses to an Xbox360. Since there is a security handshake between the controller and the Xbox, you can't just hook up (or emulate) any HID device. However you can relay the traffic from the controller to the Xbox and inject additional USB traffic.

<BEGIN BACKGROUND - FEEL FREE TO SKIP>
One option I was able to get working was emulating a PS2 controller using a Teensy2 based on this: http://procrastineering.blogspot.com/2010/12/simulated-ps2-controller-for.html
I used this in combination with a PS2 to Xbox controller adapter which does the whole USB interception thing (it also requires a standard Xbox controller to be connected to it). There were unfortunately two limitations. It can only be used with a standard xbox controller (no guitar, steering wheels, etc). Only one can be used at a time. I think there may have been some sort of hard coded address in the adapter. If a 2nd one is plugged in, the 1st one stops working.

Another option was using the facedancer: http://goodfet.sourceforge.net/hardware/facedancer21/
I got this all the way through the security handshake, but unfortunately the facedancer (using the Max3421E chip) can only support 3 endpoints and they are unidirectional (1 is read-only, 2/3 are write only). The controller uses two bi-directional endpoints, so even if I were able to fudge the descriptor and translate traffic to different endpoints, I can't manage 2 endpoints in each direction.

I did run across someone doing something very similar using a pair of Teensy2s. https://github.com/brandonlw/USBSimulator
But I ran into some trouble getting it to work.
<END BACKGROUND>

So on to my questions:
USB
How many endpoints does the Teensy2 support?
The Teensy3?

Are they all capable of bidirectional traffic?

Can I program the Teensy2 to do fairly low level USB, specifically control traffic on endpoint 0 (e.g. descriptors, vendor requests)?
The Teensy3?

Communication
It looks like there are several communication options on the Teensy2:
USB (as a serial)
USB (as other device)
Serial
SPI

The teensy 3 adds a few more:
I2C
2 more Serial

This will be primarily for HID devices, but I'd like to minimize the latency, and not unnecessarily limit my bandwidth.

If I am using a setup like Device<->PC<->Teensy#1<->Teensy#2<->Host, then I can have the two Teensies communicate via I2C,Serial, or SPI.
What is the bandwidth of using the USB port as a serial between the PC and the Teensy?
What about if I used the USB as a custom device and spoke directly to the endpoints?
What would the bandwidth be like between the Teensies using I2C?
Serial?
SPI?

I know that USB host support isn't available at the moment for the Teensy but could be in the future at some point. But there are also some host shield options, particularly this one:
http://www.circuitsathome.com/products-page/arduino-shields/usb-host-shield-for-arduino-pro-miniI understand this is supported on the Teensy2, but not the 3.
This uses the Max3421E over the SPI bus which I'm already familiar with from the FaceDancer, so is the "not supported" mean that it could likely be made to work if I write the code?
 
I'm really not very familiar with these controllers and especially their protocols, so I'm only going to answer the specific questions. While I'll try to answer as accurately as I can, please don't take these answers to mean there's an assurance this can actually work.


So on to my questions:
USB
How many endpoints does the Teensy2 support?

Seven, including endpoint zero.


The Teensy3?

All 16.

Are they all capable of bidirectional traffic?

On Teensy3, yes. Endpoints 1-15, when configured as bulk, int or isync support both in and out.

On Teensy2, no. Endpoints 1-6 are unidirectional only. You must configure each as only in or only out.

Can I program the Teensy2 to do fairly low level USB, specifically control traffic on endpoint 0 (e.g. descriptors, vendor requests)?

Teensy2 is a USB device, not a host, so any sense of the word "control traffic" is limited to responding the host's requests. In that respect, yes, you can send any data, like different vid/pid or other descriptors.

The Teensy3?

Yes, the situation is the same. Teensy3's hardware also supports USB host mode. However, there is currently no software support for host.

Communication
It looks like there are several communication options on the Teensy2:
USB (as a serial)
USB (as other device)
Serial
SPI

The teensy 3 adds a few more:
I2C
2 more Serial

For the ready-made USB options, please install Teensyduino, then look in Arduino's Tools > USB Type menu.

Both Teensy2 and Teensy3 have I2C.

Teensy3 does add 2 more serial ports.

What is the bandwidth of using the USB port as a serial between the PC and the Teensy?

Here are some benchmarks.

http://www.pjrc.com/teensy/benchmark_usb_serial_receive.html

What about if I used the USB as a custom device and spoke directly to the endpoints?

The USB code for Teensy3 is all inside hardware/teensy/cores/teensy3. For Teensy2, it's in several directories under hardware/teensy/cores/... Teensy2 has relatively simple USB hardware, where each endpoint has a pair of buffers that are accessed by the CPU as a FIFO using memory mapped registers (the CPU reads or write every byte using a loop). Teensy3 has much more advanced hardware, using DMA transfers and interrupts to notify completion of transfers. It's far more efficient, but this architecture requires much more complex code to manage memory, schedule DMA, and respond to interrupts. If you plan to edit the USB code, I would highly recommend you review the code in those directories. You'll probably find Teensy2's code much easier to understand.

What would the bandwidth be like between the Teensies using I2C?

I2C is usually either 100 kbps or 400 kbps. The protocol has significant overhead. This isn't specific to Teensy. You can learn more about I2C on many other sites.


The 1st serial port on Teensy3 also has FIFOs, and Teensy3 is simply much faster than Teensy2. Those 2 factors allow Serial1 on Teensy3 to work at much higher serial baud rates. The max speed depends on a lot of factors in your program's design, but generally Teensy2 runs out of steam somewhere around 500 kbps. A least a few people have reported success with 1 Mbit/sec on Teensy3 and faster speeds are probably possible.

If you're only connecting 2 boards, hardware Serial is the easiest way, with the most mature code that's simple to use.


SPI can be very fast, but also difficult to use in slave mode. Currently there is no SPI library supporting slave mode on either board, so you'll have to do all that work from scratch. Some people have used SPI slave mode for some projects, but it usually involves special coding specific to your needs. Teensy3 has a 4 word FIFO which makes keeping up with the data a bit easier, and also DMA which is theoretically capable of amazing things, but not simple to use. Teensy2's SPI only buffers 1 byte, so it's requires tightly coded loops to run fast.

I know that USB host support isn't available at the moment for the Teensy but could be in the future at some point. But there are also some host shield options, particularly this one:
http://www.circuitsathome.com/products-page/arduino-shields/usb-host-shield-for-arduino-pro-miniI understand this is supported on the Teensy2, but not the 3.

I recently ported that library. It's still not well tested, but recently at least one person managed to use it. Info is here:

http://forum.pjrc.com/threads/13433-USB-Host-Status?p=34969#post34969

This uses the Max3421E over the SPI bus which I'm already familiar with from the FaceDancer, so is the "not supported" mean that it could likely be made to work if I write the code?

If you use the MAX3421E, you almost certainly would want to start with that library.
 
Thanks for you quick response.
One question I totally forgot to ask. Is either the Teensy2 or 3 able to simulate a physical disconnect of the USB port, so that the host will start over with the enumeration as if it was just plugged in?

I'm really not very familiar with these controllers and especially their protocols, so I'm only going to answer the specific questions. While I'll try to answer as accurately as I can, please don't take these answers to mean there's an assurance this can actually work.
It's not a very complicated protocol, but I think I have it pretty well sorted out, it's really just an exchange of 3 or 4 vendor specific control messages on endpoint 0, after that authentication step its pretty basic HID stuff.
For anyone who is reading this and is interested in some more detail it's available here: http://brandonw.net/360bridge/doc.php

The USB code for Teensy3 is all inside hardware/teensy/cores/teensy3. For Teensy2, it's in several directories under hardware/teensy/cores/... Teensy2 has relatively simple USB hardware, where each endpoint has a pair of buffers that are accessed by the CPU as a FIFO using memory mapped registers (the CPU reads or write every byte using a loop). Teensy3 has much more advanced hardware, using DMA transfers and interrupts to notify completion of transfers. It's far more efficient, but this architecture requires much more complex code to manage memory, schedule DMA, and respond to interrupts. If you plan to edit the USB code, I would highly recommend you review the code in those directories. You'll probably find Teensy2's code much easier to understand.
I'll take a look at both, but I think I'd rather put in the extra work in the interests of being able to keep the relaying as transparent as possible (which will be difficult with unidirectional endpoints).

I2C is usually either 100 kbps or 400 kbps. The protocol has significant overhead. This isn't specific to Teensy. You can learn more about I2C on many other sites.
The 1st serial port on Teensy3 also has FIFOs, and Teensy3 is simply much faster than Teensy2. Those 2 factors allow Serial1 on Teensy3 to work at much higher serial baud rates. The max speed depends on a lot of factors in your program's design, but generally Teensy2 runs out of steam somewhere around 500 kbps. A least a few people have reported success with 1 Mbit/sec on Teensy3 and faster speeds are probably possible.
If you're only connecting 2 boards, hardware Serial is the easiest way, with the most mature code that's simple to use.
SPI can be very fast, but also difficult to use in slave mode. Currently there is no SPI library supporting slave mode on either board, so you'll have to do all that work from scratch. Some people have used SPI slave mode for some projects, but it usually involves special coding specific to your needs. Teensy3 has a 4 word FIFO which makes keeping up with the data a bit easier, and also DMA which is theoretically capable of amazing things, but not simple to use. Teensy2's SPI only buffers 1 byte, so it's requires tightly coded loops to run fast.
It sounds like the Teensy3 will definitely be a better option for me, and the serial is fast enough that there is no reason to worry about messing about with the other communication options.

I recently ported that library. It's still not well tested, but recently at least one person managed to use it. Info is here:
http://forum.pjrc.com/threads/13433-USB-Host-Status?p=34969#post34969
If you use the MAX3421E, you almost certainly would want to start with that library.
I don't know how high I would rate my experience. But I ported the python code for the FaceDancer to DotNet, and was able to get it working well enough to do a basic keyboard device emulation, and that was all on the client side, not the host side of the MaX3421E, but I'm comfortable at least to fiddle about with it.

I think I'll probably pick up a couple of Teensy3s then and try using those by themselves with the computer as a host and then maybe add the host shield into the mix at some point in the future.
 
One question I totally forgot to ask. Is either the Teensy2 or 3 able to simulate a physical disconnect of the USB port,

Yes. You can disable the USB and disconnect the (internal) 1.5K pullup resistor.

On Teensy2, Serial.end() does this for you. On Teensy3, it's not yet implemented, so you'd need to write code to access the USB registers.
 
Status
Not open for further replies.
Back
Top