HID device won't communicate under windows.

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
SA007
Posts: 7
Joined: Thu Jan 01, 2009 9:33 pm

HID device won't communicate under windows.

Post by SA007 » Mon Oct 19, 2009 3:07 pm

I've based a hardware PWM RGB controller on USB-HID, mostly copied from the Automator example.

Under Linux I've got almost everything working (GET_REPORT still acts funny, but I don't really have to use that)

Under windows is another story, It detects the device (no error on connect) but if I try to send a report I get USB_ERROR_IO back from usb-windows.c.

I compile the windows application using mingw with the usb files from Automator.

Here are what I think are the relevant code segments for this problem:
Control app (set-led.c)

Code: Select all

#include "usbcalls.h"
[...]
    if(usbOpenDevice(&dev, vid, vendor, pid, product, 1) != 0){
        fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid);
        exit(1);
    }
[...]
        buffer[0] = CUSTOM_RQ_SET_RED;
        buffer[1] = atoi(argv[2]);
        if((err = usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer, 2)) != 0){
                fprintf(stderr, "Error sending value: %s\n", usbErrorMessage(err));
                goto errorOccurred;
        }
[...]
errorOccurred:
    if(dev != NULL)
        usbCloseDevice(dev);
    return 0;
}


The pieces of relevant firmware code:

Code: Select all

static uchar expectWrite;

/* ------------------------------------------------------------------------- */
/* ------------------------ interface to USB driver ------------------------ */
/* ------------------------------------------------------------------------- */

PROGMEM char usbHidReportDescriptor[33] = {    /* USB report descriptor */
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x85, 0x01,                    //   REPORT_ID (1)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x09, 0x00,                    //   USAGE (Undefined)
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x95, 0x80,                    //   REPORT_COUNT (128)
    0x09, 0x00,                    //   USAGE (Undefined)
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
    0xc0                           // END_COLLECTION
};

uchar   usbFunctionRead(uchar *data, uchar len)
{
        data[0] = CUSTOM_RQ_GET_STATUS;
        data[1] = 255 - OCR0B;
        data[2] = 255 - OCR0A;
        data[3] = 255 - OCR1B;
        return 4;
}

uchar   usbFunctionWrite(uchar *data, uchar len)
{
  if (expectWrite == 0) return 1;
  if ((expectWrite == CUSTOM_RQ_SET_RED)|(expectWrite == CUSTOM_RQ_SET_GREEN)|(expectWrite == CUSTOM_RQ_SET_BLUE)) {
        expectWrite = 0;
        if(len < 2)
            return 0xff;        /* stall */
        switch (data[0]) {
                case CUSTOM_RQ_SET_RED:
                        OCR0B = 255 - data[1];
                        break;
                case CUSTOM_RQ_SET_GREEN:
                        OCR0A = 255 - data[1];
                        break;
                case CUSTOM_RQ_SET_BLUE:
                        OCR1B = 255 - data[1];
                        break;
        }
        return 1;
  }
  if (expectWrite == CUSTOM_RQ_SET_ALL) {
        expectWrite = 0;
        if(len < 4)
            return 0xff;        /* stall */
        OCR0B = 255 - data[1];
        OCR0A = 255 - data[2];
        OCR1B = 255 - data[3];
        return 1;
  }
  return 0;
}

uchar   usbFunctionSetup(uchar data[8])
{
    static uchar    replyBuf[4];
    usbRequest_t    *rq = (void *)data;

    usbMsgPtr = replyBuf;
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
        if(rq->bRequest == USBRQ_HID_GET_REPORT){
            if(rq->wValue.bytes[0] == CUSTOM_RQ_GET_STATUS){
                return 0xff;
            }
        }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
          expectWrite = rq->wValue.bytes[0];
          return 0xff;
        }
    }
    return 0;
}

The rest is just some includes and register settings for the pwm timers and stuff.

Almost all of the HID stuff is like a 1-on-1 copy from Automator, but I can't really get it to work at all.

Post Reply