USB: The (Other) End

For the past several weeks I’ve been building a USB device using a PIC18F2550. This time around I wanted to wrap up with a discussion of the host software. After all, if you build a USB device, it stands to reason that you want to use it from some host computer software, right? If you built something that looks like a standard device (say, a mouse) then that’s easy. You just treat it like you would any other mouse.

However, it is simpler and more flexible to build a HID (Human Interface Device) and that’s what I did. I mentioned these earlier in this series, and it is true that a mouse (and a keyboard) is a HID. But not all HIDs act like standard input devices.

You could write a complete USB driver, but that’s a lot of work. Not to mention you’d have to write a fresh driver for every operating system. That’s part of the beauty of using the HID design: All major operating systems already have a driver for HIDs. Your job is to interact with it from simpler-to-write user software.

There are a few options. The libusb library I’ve talked about before. It is very flexible, but it also is a little complex to work with when you don’t need all of its capabilities. In addition, the Windows support was limited until recently (this is the 1.0 version, not the older version which is a little quirkier).

The other option is to use the HIDAPI library. This provides a uniform interface between Linux, Mac, and Windows via different back ends. First up, I wanted to write a simple command-line interface to prove I could talk to the device.

#include <stdio.h>
#include "hidapi.h"

int main(int argc, char *argv[])
{
  int state=0;
  float v;
  
  unsigned char buf[65];
  hid_device *handle;
  if (hid_init()) return;
  printf("Hid init\n");
  handle=hid_open(0x4d8,0xf83f,NULL);   // our PID
  if (!handle) return;
  printf("Hid opened\n");
  buf[0]=0;   // send a command
  buf[1]=1;
  buf[2]=1;
  int rv1=hid_write(handle,buf,3);
  printf("Write returned %x\n",rv1);
  buf[0]=0;   // send a read command
  buf[1]=2;
  hid_write(handle,buf,2);
  hid_read(handle,buf,sizeof(buf));  // read data back
  v=(buf[3]<<8|buf[2])*5/1024.0;  // convert to voltage
  printf("Voltage=%f\n",v);
  buf[0]=0;
  buf[1]=1;
  buf[2]=0;
  hid_write(handle,buf,3);
  hid_close(handle);
  hid_exit();
}

Not very exciting, but easy to follow. The hid_init function sets up the library while the hid_open call opens my specific device. The hid_read, hid_write, and hid_close commands all do what you think they do. Finally, hid_exit cleans up anything left behind.

Quite simple. Of course, you can do plenty more, but the code from this series will allow you to do a surprising amount of USB development with a minimum of fuss.

If you are interested in more about USB, I’d suggest you start working through the Microchip examples (or the similar examples from your vendor of choice). Jan Alelson’s book USB Complete is another great reference (not to mention her resource site at http://www.lvr.com/usb.htm). If you aren’t interested in more about USB, then good news. I’m done with the USB code. At least for now.