Page 1 of 1

Making a composite device.

Posted: Mon Jun 18, 2007 11:57 pm
by spiff
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)?

Posted: Sun Feb 17, 2008 6:43 pm
by STB
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

Posted: Thu May 01, 2008 5:24 pm
by MasterAlexei
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

Posted: Thu May 01, 2008 5:31 pm
by MasterAlexei
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.

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

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.

Posted: Fri May 02, 2008 11:27 am
by MasterAlexei
Thanks, The Slow. I'll try it today after work.