It's
a common belief that USB parallel ports are simply not capable
of bit-banging. While this is *mostly* true, there are ways around the limitation. Based on the Prolific PL2305 chip, USB
parallel devices emulate a centronics or IEE1284 protocol in
hardware with no way to access the data lines programatically.
For these devices to work, a printer (or printer-like device) must be
present to read the data.
So how to get around this?
Emulate a printer.
While the most direct approach for that might be to use a microcontroller, it's really not necessary.
Studying
the Centronics protocol, when data is posted, a STROBE is
asserted. The printer then asserts BUSY until it has completed
processing the data. It then de-asserts BUSY and the process
repeats. Note that the nAck line may be ignored as some systems
transfer data between host and printer by using only the STROBE*
and BUSY signals. USB parallel devices are also compatible with
this.
So then STROBE must at a minimum must cause BUSY to assert, then later get de-asserted, by ... something.
I get by with a little help from my friends
So what can assert and de-assert the BUSY line? There
are some timing constrains that must be met. BUSY must be
asserted immediately after a STROBE and then stay asserted for
as long as we need to access a byte of data. To do this is
fairly simple. A transistor inverter (because STROBE is inverted)
that triggers a Thyristor/SCR can emulate this behavior easily.
But once the Thyristor/SCR is triggered, how do we turn turn it
off? Its anode must be pulsed to ground to reset it.
Fortunately
a $2 USB RS232 serial cable can help with this. With the
right configuration of start and stop bits combined with a character
sequence, the TX line of RS232 can generate a single pulse.
Serial data is transmitted LSB first. Data '1' is the same polarity as
the stop bit and data '0' is the same polarity as the start bit. So
0xf0 is transmitted as:
0000011111
Which produces the following:
RS232 polarities are inverted. So the data represented above will be read on the wire as:
(note
I am using a very cheap "5v" rs232 usb cable. Most USB RS232
cables are made this way as nearly all UARTS and logic made since 1980
can deal with these voltage levels. )
It's possible to generate 2 or more pulses per character as well:
_|~~~~~~~~~|_________ 0xF0
_|~~~~~|_____|~~~~~|_____ 0x1C
_|~|_|~|_|~|_|~|_|~|_ 0x55
Schematic
3 Transistor USB Parallel Port
Bit Bang Liberator / Printer Emulator
______ STROBE asserts BUSY until cleared by falling edge of RS-232 pulse (Character 0xF0)
Each time a character of 0x0F is sent, the thyristor is reset and
BUSY is de-asserted.
So why not just use the RTS or DTR line instead?
Well you can, but then you're stuck with only one other usable output
line and TX serial data. The TX line isn't very useful for much except
as a pulse generator, which is perfect for de-asserting the BUSY line.
This
gives the added benefit of freeing up the RTS and DTR lines for other purposes.
Why not just use a PIC or an Arduino?
MCU's
are getting cheaper, but USB Parallel devices can be had for as low as
$2 with free shipping. Also, some amount of programming and
hardware development must be done with an MCU. Another issue is
device drivers. USB parallel and USB serial drivers are already written
for Windows and Linux and compiled into the kernel of many
distros and even android devices. (If you've ever tried to
cross-compile android, you'll immediately appreciate this). Also, a
USB Serial and USB Parallel
port requires no programming at all. Shell scripts are
all that's needed to ouput data to either device.
To
use the android app, your device must be rooted with usb parallel
and usb serial drivers installed. Newer cyanogenmod roms (4.0
and later) have at least some support for this compiled in.
PL2303-based USB serial devices should work fine, but be
careful with CH341-UART. While basicaly identical to the PL2303,
most android releases to date do no yet include the
CH341-UART driver (although this is likely to change). USB parallel
devices are all some variant of the PL2305 (with various revisions).
My
particular device is a kindle fire with a USB OTG cable, and
powered a USB hub. The release is JellyBean 4.2 CM Otter SGT7,
but older releases have worked (GedeRom 4.0 for example).
When loaded, the USB serial device is at /dev/ttyUSB0 and the USB
parallel device in /dev/usb/lp0
For controlling the serial port RTS/DTR lines via ioctls from apps, see here