Combining Input and Feature Reports

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
emendemon
Posts: 3
Joined: Mon Jul 20, 2009 11:04 pm

Combining Input and Feature Reports

Post by emendemon » Mon Jul 20, 2009 11:31 pm

Hi all,

Hoping someone can help out with a problem I'm having.

I'm attempting to combine the features of HID-Data and HID-Mouse examples. I modified the mouse example slightly to use a single axis (X) and to use a joystick usage instead of a mouse (this works on my hardware by itself).

The problem comes when I try to combine the examples - I want the Joystick to work like a Joystick, but I want to be able to exhange feature reports to add data to my hardware (using Jan Axelson's generic_HID VB application). I don't know how to generate a report that combines input and feature on the control pipe, and still have the input report sent on an interrupt in pipe.

Here's the HID report descriptor (which works):

Code: Select all

PROGMEM char usbHidReportDescriptor[48] = { /* USB report descriptor, size must match usbconfig.h */
    0x05, 0x01,   // USAGE_PAGE (Generic Desktop)
    0x15, 0x00,   // LOGICAL MINIMUM (0)
    0x09, 0x04,   // USAGE (Joystick)
   
    0xA1, 0x01,   // COLLECTION (Application)

       0x09, 0x01,   //  USAGE (Pointer)
       0xA1, 0x00,   //  COLLECTION (Physical)
         0x95, 0x01,   //    REPORT_COUNT (1)
         0x75, 0x08,   //    REPORT_SIZE (8)
         0x15, 0x00,   //    LOGICAL_MINIMUM (0)
         0x25, 0xFF,   //    LOGICAL_MAXIMUM (255)
         0x09, 0x30,   //    USAGE (X)
         0x81, 0x02,   //    INPUT (Data,Var,Abs) 
       0xC0,   //   END_COLLECTION

       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)
         0x95, 0x04,           //   REPORT_COUNT (4)
         0x09, 0x00,           //   USAGE (Undefined)
         0xb2, 0x02, 0x01,  //   FEATURE (Data,Var,Abs,Buf)
       0xc0,                   // END_COLLECTION

    0xC0  // END_COLLECTION
};


I've also added in an IF condition to the usbFunctionSetup function in the HID-Mouse example to watch out for a Feature Report request (this is a concatenated version of the function):

Code: Select all

//......
if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
     /* we HAVE MORE THAN one report type, so WE DO look at wValue */
     //if the high byte of wValue = 3 (for Feature report type)
     if(rq->wValue.bytes[1] = 3){
          bytesRemaining = 4;
          currentAddress = 0;
          return USB_NO_MSG;  /* use usbFunctionWrite() to receive data from host */
     }
     //else, assume it was an input report, and return the reportBuffer struct
     //(which just has a single X axis
     else{
           usbMsgPtr = (void *)&reportBuffer;
           return sizeof(reportBuffer);
     }
else if(rq->bRequest == USBRQ_HID_SET_REPORT){
     /* since only feature reports can be set, we can ignore the report-ID */
     bytesRemaining = 4;
     currentAddress = 0;
     return USB_NO_MSG;  /* use usbFunctionWrite() to receive data from host */
}

// Rest of code


The interrupt function from HID-Mouse is the same, and the usbFunctionRead and usbFunctionWrite from HID-Data are the same.

Still, I get problems from the generic_HID program saying a feature report can't be read.

Thoughts?

-emen

emendemon
Posts: 3
Joined: Mon Jul 20, 2009 11:04 pm

Re: Combining Input and Feature Reports

Post by emendemon » Fri Aug 28, 2009 5:32 pm

I saw this got a lot of views.

I ended up getting it to work, so here's the code to set and get feature reports, and send input reports. Use usbFunctionSetup to route the diffrerent USB request types to their appropriate functions:

Code: Select all

usbMsgLen_t usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;

    /* The following requests are never used. But since they are required by
     * the specification, we implement them in this example.
     */
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* class request type */
        DBG1(0x50, &rq->bRequest, 1);   /* debug output: print our request */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){ 
      
      
         /* wValue: ReportType (highbyte), ReportID (lowbyte) */
         // See what ReportType was requested by right shifting the two byte word wValue, and
         // just reading the high byte
           if(rq->wValue.bytes[1] == USBRQ_HID_FEATURE){
            bytesRemaining = 255;
               currentAddress = 0;

               return USB_NO_MSG;  /* use usbFunctionRead() to obtain data */            
         }
         // If the request wasn't for a feature report, return an input report
         else if(rq->wValue.bytes[1] == USBRQ_HID_INPUT){
               usbMsgPtr = (void *)&reportBuffer;
            return sizeof(reportBuffer);
         }
       
      }else if(rq->bRequest == USBRQ_HID_SET_REPORT){
            /* since we have only one report type, we can ignore the report-ID */
            bytesRemaining = 255;
            currentAddress = 0;
            return USB_NO_MSG;  /* use usbFunctionWrite() to receive data from host */
     
      }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
            usbMsgPtr = &idleRate;
            return 1;
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
            idleRate = rq->wValue.bytes[1];
        }
    }else{
        /* no vendor specific requests implemented */
    }
    return 0;   /* default for not implemented requests: return no data back to host */
}




Post Reply