Making a composite device.

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
spiff
Rank 1
Rank 1
Posts: 24
Joined: Tue Apr 17, 2007 1:00 am
Location: Virum, Denmark
Contact:

Making a composite device.

Post by spiff » Mon Jun 18, 2007 11:57 pm

Hello all.

The next step in my C64 USB keyboard implementation is trying to make a composite device that handles both the keyboard and two digital joysticks. I have made each of these work individually, that is two joysticks on one uController and the keyboard on a different one.

I tried to create a combined report (still only 8 bytes) containing both the keyboard and one joystick (the joystick report is only one byte), but aparently Windows cannot decide whether to use the keyboard or joystick driver for this device, so it ends up saying device installation failed, and nothing works.

I was thinking that I could make two different reports: one for the keyboard and one for the two joysticks. Is there any reason why this should not work?

For this, I guess I need to have a report ID in the reports. This should be no problem, except that the keyboard report can then not conform to the boot specification. Does anyone know if there would be a problem implementing a boot device (keyboard) that does not use the boot protocol when running in normal report mode, but does when the boot protocol is used? I assume this is the reason why there are SET_PROTOCOL and GET_PROTOCOL functions (which I have currently implemented, but which do nothing).

How do I make the composite device with two different reports. Does the setup request ask for which report to return, or is that something my application has to decide (e.g. switching between the two)?

STB
Posts: 7
Joined: Tue Jan 15, 2008 8:43 am

Post by STB » Sun Feb 17, 2008 6:43 pm

Hi !

Making a device supporting different kinds (length) of reports, the easiest way is to use ReportIDs.

The report structure canges a little bit (Device Class Definition for HID V1.11, 5.6 Reports, page 17).

You must add the Report_ID statement in your HID Descriptor. My example shows a descriptor for a keyboard with embedded mouse.

Code: Select all

char usbHidReportDescriptor[83] = {                                         //83
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, MouseID,                 //   REPORT_ID (77)
    0x05, 0x09,                    //   USAGE_PAGE (Button)
    0x19, 0x01,                    //   USAGE_MINIMUM (Button 1)
    0x29, 0x08,                    //   USAGE_MAXIMUM (Button 8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0x05, 0x01,                    //   USAGE_PAGE (Generic Desktop)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x02,                    //     REPORT_COUNT (2)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xc0,                          //   END_COLLECTION
    0xc0,                          // END_COLLECTION
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, KeyboardID,              //   REPORT_ID (75)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0xE0,                    //   USAGE_MINIMUM (Left Ctrl)
    0x29, 0xE7,                    //   USAGE_MAXIMUM (Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
   0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)   
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved, No Event)
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Var,Abs)
    0xc0                           // END_COLLECTION
};


You need 2 reportBuffers, the element with index 0 contains the ID

Code: Select all

reportBufferMouse[3] = {MouseID, 0, 0};
reportBufferKBD[3]   = {KeyboardID, 0, 0};


and 2 routines sending the buffers

Code: Select all

      if(usbInterruptIsReady() && ((TB_pos_x != oldTB_pos_x) || (TB_pos_y != oldTB_pos_y)))
      { /* we can send another relative coordinate */
            buildReportTrackball();
            usbSetInterrupt(reportBufferMouse, sizeof(reportBufferMouse));
           
        }

      if(usbInterruptIsReady() && (key_state != old_key_state))
      { /* we can send another Keysequence */
            buildReportKBD();
            usbSetInterrupt(reportBufferKBD, sizeof(reportBufferKBD));
       }


I hope this helps.
It is very easy to add more devices (joysticks....), each device simply needs an unique Report_ID. Report_ID 0 is reserved, do not use.

Have fun!

Regards,

STB

MasterAlexei
Posts: 4
Joined: Tue Apr 29, 2008 9:53 pm
Location: Germany
Contact:

Post by MasterAlexei » Thu May 01, 2008 5:24 pm

Hello there.
I'd try to do it so, how you show above.
But I'd used a keyboard and Custom device Reports. It was not recognised as right Report Descriptor
Here it is:

Code: Select all

char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {

    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, REPORT_ID_0,             //   REPORT_ID (0)
    // 8

    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    // 16
   
    0x95, 0x05,                    //   REPORT_COUNT (5)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x05, 0x08,                    //   USAGE_PAGE (LEDs)
    0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock)
    0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)
    0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    // 12
   
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x03,                    //   REPORT_SIZE (3)
    0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)
    // 6

    0x95, 0x05,                    //   REPORT_COUNT (5)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    // 17

    0xc0,                          // END_COLLECTION
    // 1

    0x05, 0x0c,                    // USAGE_PAGE (Consumer Devices)
    0x09, 0x01,                    // USAGE (Consumer Control)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, REPORT_ID_1,             // REPORT ID (1)
    0x09, 0xe9,                    //   USAGE (Volume Up)
    0x09, 0xea,                    //   USAGE (Volume Down)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x15, 0x01,                    //   LOGICAL_MINIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x09, 0xe2,                    //   USAGE (Mute)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x06,                    //   INPUT (Data,Var,Rel)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x05,                    //   REPORT_COUNT (5)
    0x81, 0x07,                    // INPUT (Cnst,Var,Rel)
    // 40

    0x95, 0x06,                    //   REPORT_COUNT (6)
    0x75, 0x03,                    //   REPORT_SIZE (8)
    0x81, 0x03,                    // INPUT (Cnst,Var,Abs)
    // 6

    0xc0                           // END_COLLECTION
    // 1
};

It's shows as HID device, but with exclamation sight on it in Device Manager.
What did I wrong?
Thanks in advance.
Alexei

MasterAlexei
Posts: 4
Joined: Tue Apr 29, 2008 9:53 pm
Location: Germany
Contact:

Post by MasterAlexei » Thu May 01, 2008 5:31 pm

In a last REPORT SIZE i entered frong size. Its already corrected, but still not functioning.
USB_CFG_INTERFACE_SUBCLASS is switched off too.
I already tryed to set USB_CFG_INTERFACE_PROTOCOL to 0 and to 1. Still no function.

The Slow

Post by The Slow » Fri May 02, 2008 11:24 am

Code: Select all

PROGMEM char usbHidReportDescriptor[70] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x4b,                    //   REPORT_ID (75)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0,                          // END_COLLECTION
    0x05, 0x0c,                    // USAGE_PAGE (Consumer Devices)
    0x09, 0x01,                    // USAGE (Consumer Control)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x4c,                    //   REPORT_ID (76)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x09, 0xe9,                    //   USAGE (Volume Up)
    0x09, 0xea,                    //   USAGE (Volume Down)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x02,                    //   REPORT_COUNT (2)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x09, 0xe2,                    //   USAGE (Mute)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x81, 0x06,                    //   INPUT (Data,Var,Rel)
    0x95, 0x05,                    //   REPORT_COUNT (5)
    0x81, 0x01,                    //   INPUT (Cnst,Ary,Abs)
    0xc0                           // END_COLLECTION
};


This descriptor for a composit device works fine maybe you can use it as a startpoint.

MasterAlexei
Posts: 4
Joined: Tue Apr 29, 2008 9:53 pm
Location: Germany
Contact:

Post by MasterAlexei » Fri May 02, 2008 11:27 am

Thanks, The Slow. I'll try it today after work.

Post Reply