Howto: Talk to arbitrary USB devices with Processing (1.0 Beta)

I’ve been playing with the Processing language (http://processing.org) a little bit and liking it so far. For anyone not familiar, it’s a Java-based rapid-prototyping language that includes very friendly libraries for graphics, sound, video and select hardware (e.g. serial port). One thing I couldn’t find much info on was talking to arbitrary USB devices (not USB-to-serial based gadgets, but sending and receiving raw packet-level data).

Anyway, I found a solution that works in Processing with only minimal tweaking. You need:

Processing (of course) – http://www.processing.org
libusb or libusb-win32 – http://libusb-win32.sourceforge.net (Windows) or http://libusb.wiki.sourceforge.net/ (Linux)
Libusb Java wrapper – http://libusbjava.sourceforge.net/wp/

I only tried this on Windows so far, so the following assumes a Windows installation.

(I know, wrappers upon wrappers. So in the end you end up with device -> OS -> libusb -> libusbjava native DLL -> libusbjava JNI wrapper -> Processing. Probably not the most efficient approach in the world, but in the era of multi-GHz machines I’m not sweating too hard about it :-)

Follow the author’s recommendations on setting up libusb-win32 for your device, if it’s not already been done. Then, (for Windows users) extract the LibusbJava.dll file and drop it somewhere Processing/Windows can find it. The author recommends \Windows\System or equivalent; if this seems a bit forward, dropping it in the same directory as processing.exe works fine too.

Finally, making the library appear for Processing: create a new folder(-nest) for it in Processing’s libraries folder (blahblah\processing-0135\libraries\libusbjava\library), and drop the .jar file in it. Rename it to something more sane; Processing doesn’t seem to like all those extra dots and numerals. After renaming the .jar file sanely and restarting Processing, it will appear in the Sketch->Import Library menu. Clicking on the menu item automagically fishes out the correct class names and adds the appropriate (import…) lines to your sketch. From here on out, programming for the libusbjava wrapper appears to follow the actual libusb API pretty closely.

Here’s the program I tested it with. All it does is connect to a Rez/Drmn trance vibrator, send a USB packet to turn the motor on at about 2/3 intensity, then exit.


import ch.ntb.usb.testApp.*; // these four lines were automatically added by clicking it
import ch.ntb.usb.*; // on Processing's Sketch -> Import Library menu item
import ch.ntb.usb.usbView.*; // ...
import ch.ntb.usb.logger.*; // Some of these can probably be removed safely.

void setup()
{
noLoop();
}

void draw()
{
LibusbJava.usb_init(); // required inits for libusb-win32
LibusbJava.usb_find_busses(); //
LibusbJava.usb_find_devices(); //

// retrieve a object tree representing the bus with its devices and
// descriptors
Usb_Bus bus = LibusbJava.usb_get_busses();

// Find a specific USB device on the bus (by its VID/PID) and return a handle to the device in 'dev'
// This diverges a bit from native libusb-win32 code in that you don't have to loop through all the devices/busses searching for it.
Device dev = USB.getDevice((short) 0x0b49, (short) 0x064f); // VID/PID combination of Drmn' Trance Vibe device

// Note: Since this is just a quick n dirty "hey, is this possible?" test, I've added no error checking whatsoever.
// For anything more than a tightly-controlled quick hack / demo, you will want to do so!! (for starters, check if the device was found at all...)

try {
// data to write to the device. I don't want to write any data, so leaving this array empty.
byte[] data = new byte[] {};
// data read from the device
byte[] readData = new byte[data.length];

// open the device with configuration 1, interface 0 and without
// altinterface
// this will initialise Libusb for you
dev.open(1, 0, -1);

// ^^ Note, this may also diverge from native libusb-win32; I've never seen the choice of "-1" for alt. interface before (I assume it's interpreted as "any/all/none/don't-care"), but it seems to work.

// This device uses Control messages on endpoint 0. The following packet turns ON the motor at about 2/3 intensity (0xAA).

// Fields are: Request type (0x41-Out+Write), bRequest, WValue, wIndex, byte[] data, size, timeout, bool reopenOnTimeout
dev.controlMsg(0x41, 0x00, 0xAAAA, 0x0000, data, 0, 1000, false);

// The "reopenOnTimeout" field is a new one. It sounds either flaky-hardware-friendly or extremely dangerous.

// ok, motor turned on! I'm satisfied that you can control arbitrary USB devices from Processing at the raw (bulk/interrupt) packet level, so this is as far as I go for now.

// close the device
dev.close();
} catch (USBException e) {
// if an exception occures during connect or read/write an exception
// is thrown
e.printStackTrace();
}
}

7 Responses to “Howto: Talk to arbitrary USB devices with Processing (1.0 Beta)”

  1. Steve Witham says:

    Tim–

    Thanks!! This is just what I need for a project of mine! I hope it works on the Mac, Darwin being BSD underneath; I started looking at the Mac OS standard IO setup and just slid back down the front of the learning curve.

    –Steve

  2. Josh says:

    Hi,

    Could you post the code that you are running on the avr please? I am stuck at this stage. I dont throw errors for the controlmsg but have no idea how to handle the msg itself on the avr.

    thanks

  3. Tim says:

    @Josh – There’s no AVR… the gadget I was writing to in this example uses PIC assembler.
    If it helps at all, the schematics and firmware source are at http://tim.cexx.org/projects/vibe/resource_v2.htm

    The Control Transfer should produce a raw 8-byte packet received by your firmware client; what data you send and how to handle it on the receiving end (unless you’re implementing some standard class, e.g. HID) is up to you. If you haven’t already, have a look at USB In A Nutshell: http://www.beyondlogic.org/usbnutshell/
    This explains the format of all the standard USB control messages and etc…and much lighter reading than the full USB spec!

  4. rsb says:

    Hi,

    I’ve tried following your setup, and processing (2.2.1) returns this error, while highlighting the
    “LibusbJava.usb_init(); ” line.

    A library relies on native code that’s not available.
    Or only works properly when the sketch is run as a 64-bit application.

    Can you think of a reason this is occuring and way to solve it? Your attention and help is greatly appreciated, thanks for writing this post :)

    rsb

  5. John says:

    I am getting the same error as rsb i.e. “A library relies on native code that’s not available.
    Or only works properly when the sketch is run as a 64-bit application.”

  6. uCHobby says:

    I am having the same issue. 64-Bit application… when I try to build/run.

    Has anyone figured this out? I’m on Win 8.1

  7. Tom says:

    Yes I am having the same problem as the above three. Please respond if solution has been found.

Leave a Reply