V-USB tutorial continued: HID mouse
Wow, my AVR ATtiny USB tutorial here I got featured in Hack a Day! Motivated by the influx of readers, I decided to find out how to make a USB HID (human interface device) mouse.
V-USB examples already contain an example of this, so I digged in to see what is different in usbconfig.h compared to the one we finished in my tutorial. It seems only a few things need changing:
USB_CFG_HAVE_INTRIN_ENDPOINTneeds to be set to have an additional endpointUSB_CFG_INTR_POLL_INTERVALset to 100 ms instead of 10 in templateUSB_CFG_IMPLEMENT_FN_WRITEis not needed, nor is …FN_READ (define both to 0)- Device ID and name need to be changed. I’ll just use the same ID as they did
USB_CFG_DEVICE_CLASSis set to 0, not 0xffUSB_CFG_INTERFACE_CLASSset to 3 instead of 0USB_CFG_HID_REPORT_DESCRIPTOR_LENGTHdefined to match the structure’s length
That’s it! So here are the defines I changed:
#define USB_CFG_HAVE_INTRIN_ENDPOINT 1
#define USB_CFG_INTR_POLL_INTERVAL 100
#define USB_CFG_IMPLEMENT_FN_WRITE 0
#define USB_CFG_IMPLEMENT_FN_READ 0
#define USB_CFG_DEVICE_ID 0xe8, 0x03
#define USB_CFG_DEVICE_NAME 'M', 'o', 'u', 's', 'e'
#define USB_CFG_DEVICE_NAME_LEN 5
#define USB_CFG_DEVICE_CLASS 0
#define USB_CFG_INTERFACE_CLASS 3
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 52
OK. So what about main.c? Turns out the changes are rather straightforward:
- Report descriptor is defined for our HID device, outlining a simple mouse status report
- The described struct for the report is implemented
- Make the device to respond to a few required request
- In the main loop, when ever USB interrupt is ready, send our report buffer
That’s actually it. The V-USB example uses a nice 10.6 fixed point sine and cosine to draw circles with the mouse, but I chose to have some erratic motion with a pseudo-random number generator. Note that with a bit of extra motion and erratic mouse clicks, you could really drive a user insane!
You can find the complete main.c (as well as usbconfig.h and the schematic) from this project zip file and study the usbHidReportDescriptor (just a string of numbers) and usbFunctionSetup() (really straightforward) on your own, but here’s the “meat” of the code – report structure and new main function inner loop:
typedef struct{
uchar buttonMask;
char dx;
char dy;
char dWheel;
} report_t;
// ...
int main() {
int rand = 1234; // initial value
// ...
while(1) {
wdt_reset(); // keep the watchdog happy
usbPoll();
if(usbInterruptIsReady()) { // if the interrupt is ready, feed data
// pseudo-random sequence generator, thanks to Dan Frederiksen @AVRfreaks
// http://en.wikipedia.org/wiki/Linear_congruential_generator
rand=(rand*109+89)%251;
// move to a random direction
reportBuffer.dx = (rand&0xf)-8;
reportBuffer.dy = ((rand&0xf0)>>4)-8;
usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
}
}
}
Thanks for reading! I might do a USB keyboard tomorrow, so I do recommend checking back soon or subscribing to the RSS feed. :)
Update: I didn’t make a USB keyboard tutorial after all, but opted instead to make a USB password generator. However, I recently stumbled upon this nice post that covers USB keyboards with V-USB and Arduino, so it might be worth to check it out:
http://petrockblog.wordpress.com/2012/05/19/usb-keyboard-with-arduino-and-v-usb-library-an-example/