Combining the Mouse, Keyboard, Joystick, GenericHID, and CDC demo

394 views
Skip to first unread message

Morten Enemark Lund

unread,
May 28, 2009, 7:59:21 AM5/28/09
to myusb-sup...@googlegroups.com
Hi Dean

I just read you blog on LUFA 2.0. Sounds really good. However, it seems that LUFA always changes just when I have spent time trying to put things together ;)

I have run into a problem combining some of the device-demos in one composite device. I managed to combine the Keyboard, Mouse, Joystick, and Generic HID demo. So far it worked fine, and I could easily add all my application specific code. 

The problem starts when I try to also add CDC functionality. It simply stops working. Connecting the device, I get an errror "This device cannot start. (Code 10)". 

Are there any obvious issues that I may have missed when adding the CDC device, or any good tips for debugging the problem. I did add an "interface association" to link the to CDC interfaces. I placed the files (without application specific code)  here if you have any good ideas. (I am using svn rev. 561)

Is it at all possible to combine that many interfaces in one device? Really hope somebody is able to help.

Btw. I am looking forward to seeing how easy this task is with the new API of LUFA. 

Best regards
Morten

--
Morten Enemark Lund,
M.Sc. Medical devices.
TKS A/S, Department of Health Science and Technology, Aalborg University

Dean Camera

unread,
May 28, 2009, 8:17:21 AM5/28/09
to LUFA (Formerly MyUSB) Support
Morten,

You've run out of endpoints; the largest USB AVR (the AT90USB1287)
only has 7 of them, so you've gone way over. No way around that I'm
afraid if you want to keep multiple discrete interfaces, but you can
combine all the HID classes into a single interface and differentiate
between them with the HID report IDs. That will condense your code to
only 5 endpoints (+ control) but will reduce the number of reports per
interface you can generate, so it's a tradeoff.

> I just read you blog on LUFA 2.0. Sounds really good. However, it seems that LUFA always changes just when I have spent time trying to put things together ;)

You weren't on the DorkbotPDX IRC chatroom, were you? I just got a
transcript from there where some of the members were discussing LUFA
and its ever-changing API, and they weren't kind (to put it mildly).
I've never had a half-joking death threat made against me before now,
so that's a first.

However, they do have a point; as although I document the changes
between each version in the migration page, the fact is that people
aren't going to accept LUFA until the API is stable, so that it "just
works". That's what I'm leaning towards now; the underlying APIs are
essentially rock-solid now after the latest round of fixups, and the
new class layers mean even more stability. Once this next release is
made, my goal is to retain compatibility as much as possible, rather
than keep shuffling things around for the maximum performance.

- Dean

On May 28, 9:59 pm, Morten Enemark Lund <mel...@gmail.com> wrote:
> Hi Dean
> I just read you blog on LUFA 2.0. Sounds really good. However, it seems that
> LUFA always changes just when I have spent time trying to put things
> together ;)
>
> I have run into a problem combining some of the device-demos in one
> composite device. I managed to combine the Keyboard, Mouse, Joystick, and
> Generic HID demo. So far it worked fine, and I could easily add all my
> application specific code.
>
> The problem starts when I try to also add CDC functionality. It simply stops
> working. Connecting the device, I get an errror "This device cannot start.
> (Code 10)".
>
> Are there any obvious issues that I may have missed when adding the CDC
> device, or any good tips for debugging the problem. I did add an "interface
> association" to link the to CDC interfaces. I placed the files (without
> application specific code)  here <http://www.hst.aau.dk/~mel/combined/>if

Morten Enemark Lund

unread,
May 28, 2009, 9:17:37 AM5/28/09
to myusb-sup...@googlegroups.com
Hi Dean

On Thu, May 28, 2009 at 14:17, Dean Camera <abcmi...@gmail.com> wrote:

 You've run out of endpoints; the largest USB AVR (the AT90USB1287)
only has 7 of them, so you've gone way over.


Ahh.. That makes sense. I think have read about that limitation somewhere, but forgot about it again. 

 
No way around that I'm
afraid if you want to keep multiple discrete interfaces, but you can
combine all the HID classes into a single interface and differentiate
between them with the HID report IDs. That will condense your code to
only 5 endpoints (+ control) but will reduce the number of reports per
interface you can generate, so it's a tradeoff.
.
That sounds acceptable. Then there should be enough endpoints. Btw. is it possible to drop some endpoints in the ConfigurationDescriptor, or are the number of endpoints defined for a specific sub-class? For example; I don't use the keyboardOUT endpoint, so I would like not to include that one.  

Are there any examples in LUFA on how to combine different reports in the same descriptor using the report ID. Also, how do I know which report the host is requesting if more reports are to be sent though the same endpoint. 


> I just read you blog on LUFA 2.0. Sounds really good. However, it seems that LUFA always changes just when I have spent time trying to put things together ;)

You weren't on the DorkbotPDX IRC chatroom, were you? I just got a
transcript from there where some of the members were discussing LUFA
and its ever-changing API, and they weren't kind (to put it mildly).
I've never had a half-joking death threat made against me before now,
so that's a first.


I wasn't at the IRC chat room, and I hope you did notice the smiley at the end of the line ;-) 
I am not making death treats. I think LUFA has probably save me from month of work trying sort out the bad USB demos from Atmel.  It just my own bad timing, that I always wrap things up, just before there is an update to LUFA. 
 
Best regards 
Morten

Michael Hennebry

unread,
May 28, 2009, 11:01:58 AM5/28/09
to LUFA (Formerly MyUSB) Support
On Thu, 28 May 2009, Dean Camera wrote:

> However, they do have a point; as although I document the changes
> between each version in the migration page, the fact is that people
> aren't going to accept LUFA until the API is stable, so that it "just
> works". That's what I'm leaning towards now; the underlying APIs are
> essentially rock-solid now after the latest round of fixups, and the
> new class layers mean even more stability. Once this next release is
> made, my goal is to retain compatibility as much as possible, rather
> than keep shuffling things around for the maximum performance.

There is a standard way of handling such things:

1. New and improved is available if one asks for it.
Old and stable is the default.
2. New and improved is the default.
Old and stable is available if one asks for it.
3. Old is deprecated.
4. Old is gone.

Of course, if new and improved and old and stable can be used together,
one can skip as many of the steps as one wants.

--
Michael henn...@web.cs.ndsu.NoDak.edu
"Pessimist: The glass is half empty.
Optimist: The glass is half full.
Engineer: The glass is twice as big as it needs to be."

Dean Camera

unread,
Jun 1, 2009, 4:48:05 AM6/1/09
to LUFA (Formerly MyUSB) Support
Michael,

> 1. New and improved is available if one asks for it.
> Old and stable is the default.
> 2. New and improved is the default.
> Old and stable is available if one asks for it.
> 3. Old is deprecated.
> 4. Old is gone.

This is a unique situation where the old isn't deprecated at all. The
API is in lockdown with the current public SVN commit, and will now
remain consistent with each version. The only breaking change really
will be the removal of the scheduler, although users can either roll
their own or copy over the scheduler from previous releases into their
projects. User code from the next release on should remain stable
between upgrades.

The changes I'm currently working on are the abstraction drivers.
While all the demos will change over to the abstraction layers from
the next version, there's no reason why users can't keep their
existing code that uses the low level LUFA APIs, rather than change
their code all over again. The class drivers are to be used in
conjunction with the low level APIs for convenience, to both simplify
the user code and to allow for bugfixes in the class drivers to
automatically be applied each time the library is upgraded.

All in all I expect one more wave of grumbling with the next release
from the minor user code changes required, but smooth sailing from
then on.

- Dean

On May 29, 1:01 am, Michael Hennebry <henne...@web.cs.ndsu.nodak.edu>
wrote:
> On Thu, 28 May 2009, Dean Camera wrote:
> > However, they do have a point; as although I document the changes
> > between each version in the migration page, the fact is that people
> > aren't going to accept LUFA until the API is stable, so that it "just
> > works". That's what I'm leaning towards now; the underlying APIs are
> > essentially rock-solid now after the latest round of fixups, and the
> > new class layers mean even more stability. Once this next release is
> > made, my goal is to retain compatibility as much as possible, rather
> > than keep shuffling things around for the maximum performance.
>
> There is a standard way of handling such things:
>
> 1.  New and improved is available if one asks for it.
>      Old and stable is the default.
> 2.  New and improved is the default.
>      Old and stable is available if one asks for it.
> 3.  Old is deprecated.
> 4.  Old is gone.
>
> Of course, if new and improved and old and stable can be used together,
> one can skip as many of the steps as one wants.
>
> --
> Michael   henne...@web.cs.ndsu.NoDak.edu

Dean Camera

unread,
Jun 1, 2009, 4:56:10 AM6/1/09
to LUFA (Formerly MyUSB) Support
Morten,

> That sounds acceptable. Then there should be enough endpoints. Btw. is it
> possible to drop some endpoints in the ConfigurationDescriptor, or are the
> number of endpoints defined for a specific sub-class? For example; I don't
> use the keyboardOUT endpoint, so I would like not to include that one.

Yes, each class has mandated endpoints. In the case of the HID
interfaces, it is mandated that each HID device carries an interrupt
type IN endpoint for device->host reports, but the OUT endpoint can be
omitted. If the OUT endpoint does not exist in a device which accepts
reports from the host, the Req_SetReport HID class control request
will be used instead for the transfer.

In the keyboard's case, all you need to do would be to remove the OUT
endpoint's descriptor (remember to remove it from the struct
definition in Descriptors.h too!), decrement the number of endpoints
in the keyboard interface, and change the keyboard HID report
descriptor to remove the references to the LED reports. That means
removing the following portion of the KeyboardReport descriptor:

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, Variable,
Absolute) */
0x95, 0x01, /* Report Count
(1) */
0x75, 0x03, /* Report Size
(3) */
0x91, 0x03, /* Output (Const, Variable,
Absolute) */

> Are there any examples in LUFA on how to combine different reports in the
> same descriptor using the report ID. Also, how do I know which report the
> host is requesting if more reports are to be sent though the same endpoint.

No LUFA examples as of yet - the KeyboardMouse demo shows off
combining multiple HID interfaces, but not combined HID interfaces.
Sending multiple different reports through the same HID interface
means that you reduce the number of reports possible per second, but
that's not an issue unless you have many interfaces all trying to
report something at once. You need to combine the KeyboardReport and
MouseReport descriptors into one giant HID descriptor, and prefix each
one with HID "Report ID" elements to give each report a unique non-
zero ID. When report IDs are used, it's simply a case of sending the
appropriate report prefixed with it's ID - so if you give the Mouse
report an ID of 0x01, you just add a 0x01 to the start of each mouse
report.

The host doesn't indicate what report it wants, because it doesn't
know/care -- it's up to you to only send relevant reports to the host
when the report's data changes.

- Dean

On May 28, 11:17 pm, Morten Enemark Lund <mel...@gmail.com> wrote:
> Hi Dean
>

Morten Enemark Lund

unread,
Jun 3, 2009, 3:59:19 AM6/3/09
to myusb-sup...@googlegroups.com
Hi Dean,

On Mon, Jun 1, 2009 at 10:56, Dean Camera <abcmi...@gmail.com> wrote:
 
Yes, each class has mandated endpoints. In the case of the HID
interfaces, it is mandated that each HID device carries an interrupt
type IN endpoint for device->host reports, but the OUT endpoint can be
omitted. If the OUT endpoint does not exist in a device which accepts
reports from the host, the Req_SetReport HID class control request
will be used instead for the transfer.

Thanks. I managed to remove the keyboard OUT endpoint, and it works fine. I want to save as many endpoints as possible, because the program needs to run on the ATUSB162, which only has four programmable endpoints. I haven't begun combining the HID reports yet, but with your description and the USB spec. I think I understand how to proceed. 

Btw. is it also possible to remove endpoints from the CDC demo, or will that break the way windows talks to CDC devices? I would like to remove the CDC-notification endpoint, as don't use that anyway. 

The only problem still haunting me is adding the CDC interfaces. I think I got the descriptors and all the firmware correct. When I don't change the PID, the system shows up as 3 devices; mouse, keyboard and unknown. That is understandable since windows don't know what drivers to install. If I change the PID to match that in the *.INF file from the CDC deomo, the CDC interface starts working but the keyboard/mouse part completely disappears. I now only see one device. 

My guess is that the driver take over the entire device. What changes can I make in the *.INF file to prevent this?

Hope you can help.
Morten

Dean Camera

unread,
Jun 3, 2009, 4:10:11 AM6/3/09
to LUFA (Formerly MyUSB) Support
Morten,

> Btw. is it also possible to remove endpoints from the CDC demo, or will that
> break the way windows talks to CDC devices? I would like to remove the
> CDC-notification endpoint, as don't use that anyway.

Unfortunately, no. The CDC standard requires them all, which is a
right pain the the proverbial. I think the drivers on some OSes don't
mind if you remove one or more of them, but it's not advisable as that
might change between OS versions.

Actually, I was thinking of experimenting with giving the notification
endpoint an address outside the AVR's range, so that the host will not
connect it properly. The AVR's USB controller should just NAK any
polls from the host when it queries the disabled endpoint, but I need
to actually test this.

> The only problem still haunting me is adding the CDC interfaces. I think I
> got the descriptors and all the
> firmware<http://www.hst.aau.dk/~mel/combined> correct.
> When I don't change the PID, the system shows up as 3 devices; mouse,
> keyboard and unknown. That is understandable since windows don't know what
> drivers to install. If I change the PID to match that in the *.INF file from
> the CDC deomo, the CDC interface starts working but the keyboard/mouse part
> completely disappears. I now only see one device.

You need to ensure that your device descriptor indicates no particular
overall device class (i.e. set the Class, Subclass and Protocol in the
device descriptor to all 0x00s) or the CDC driver will attempt to bind
to all the interfaces within the device, and just discard the HID
ones. Instead, you need to modify the INF descriptor in the same way
as the DualCDC demo, where you add "&MI_XX" - where XX is the
interface number of the CDC interface - to the end of each VID/PID
reference to make the INF file bind the CDC driver to only the
interfaces you want.

When done in this manner (compound device of no overall type, INF file
which only binds per-interface) you can have two dissimilar classes in
your device which will be enumerated seperately. Note that in the case
of the CDC class you will need to add in an Interface Association
Descriptor (IAD) in the same manner as the DualCDC demo so that the
CDC driver binds one instance to all three CDC endpoints in the two
CDC interfaces.

Actually, the DualCDC demo is a great starting point for you, since it
is doing almost exactly as you are trying to do, although it uses two
of the same classes in it rather than two dissimilar classes. The
theory is the same, however, so check out the DualCDC demo's INF and
descriptors.

- Dean

On Jun 3, 5:59 pm, Morten Enemark Lund <mel...@gmail.com> wrote:
> Hi Dean,
>
> On Mon, Jun 1, 2009 at 10:56, Dean Camera <abcminiu...@gmail.com> wrote:
> > Yes, each class has mandated endpoints. In the case of the HID
> > interfaces, it is mandated that each HID device carries an interrupt
> > type IN endpoint for device->host reports, but the OUT endpoint can be
> > omitted. If the OUT endpoint does not exist in a device which accepts
> > reports from the host, the Req_SetReport HID class control request
> > will be used instead for the transfer.
>
> Thanks. I managed to remove the keyboard OUT endpoint, and it works fine. I
> want to save as many endpoints as possible, because the program needs to run
> on the ATUSB162, which only has four programmable endpoints. I haven't begun
> combining the HID reports yet, but with your description and the USB spec. I
> think I understand how to proceed.
>
> Btw. is it also possible to remove endpoints from the CDC demo, or will that
> break the way windows talks to CDC devices? I would like to remove the
> CDC-notification endpoint, as don't use that anyway.
>
> The only problem still haunting me is adding the CDC interfaces. I think I
> got the descriptors and all the
> firmware<http://www.hst.aau.dk/~mel/combined> correct.

Morten Enemark Lund

unread,
Jun 4, 2009, 6:04:01 AM6/4/09
to myusb-sup...@googlegroups.com
HI Dean 

On Wed, Jun 3, 2009 at 10:10, Dean Camera <abcmi...@gmail.com> wrote:

Actually, I was thinking of experimenting with giving the notification
endpoint an address outside the AVR's range, so that the host will not
connect it properly. The AVR's USB controller should just NAK any
polls from the host when it queries the disabled endpoint, but I need
to actually test this.


That is interesting. Am looking for all possible ways to save endpoints. Can I also try the same, or does it require a little more knowledge of the low-level LUFA stuff? 

Thanks for your tips on the INF file. By adding the interface number to the PID I got the driver working. So my combined keyboard/mouse/CDC is now working. If anyone needs it just let me know.

Right now I am working on combining the HID descriptors to get keyboard and mouse into one descriptor. When that works I will add joystick and generic HID. The last step is then to add all my application specific code. 

I have few questions, that I hope someone here might help me with. 

1. What report must be send, if the host issues a GetReport request and all HID reports are combined in one descriptor. Do I just send all reports one after each other? 

2. What is the correct procedure to send more report thought the same endpoint?   Is the code below correct? 

3. Are there difference between sending reports though the control endpoint (GetReport requests) and the report endpoint?

Best regards
/Morten



TASK(USB_Combined)
{
uint8_t  ButtonStatus_LCL = Buttons_GetStatus();
/* Set report IDs of the keyboard and mouse report*/
KeyboardReportData.ReportID = 1;
MouseReportData.ReportID = 2;
/* Add stuff to the keyboard and mouse report if button is pressed. */
if (ButtonStatus_LCL & BUTTONS_BUTTON1)
{
 KeyboardReportData.KeyCode[0] = 0x04; // A
 MouseReportData.Y =  1;
}
/* Check if the USB system is connected to a host and report protocol mode is enabled */
if (USB_IsConnected)
{
/* Select the Combined Report Endpoint */
Endpoint_SelectEndpoint(COMBINED_IN_EPNUM);

/* Check if Keyboard Endpoint Ready for Read/Write */
if (Endpoint_IsReadWriteAllowed())
{
/* Write Keyboard Report Data */
Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));

/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();

/* Clear the report data afterwards */
memset(&KeyboardReportData, 0, sizeof(KeyboardReportData));
/* Write Mouse Report Data */
Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));

/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();

/* Clear the report data afterwards */
memset(&MouseReportData, 0, sizeof(MouseReportData));

Morten Enemark Lund

unread,
Jun 4, 2009, 12:58:42 PM6/4/09
to myusb-sup...@googlegroups.com
Hi 

I managed to solve these problems myself. 


Right now I am working on combining the HID descriptors to get keyboard and mouse into one descriptor. When that works I will add joystick and generic HID. The last step is then to add all my application specific code. 

I have few questions, that I hope someone here might help me with. 

1. What report must be send, if the host issues a GetReport request and all HID reports are combined in one descriptor. Do I just send all reports one after each other? 

The reportID of the requested report is defined by the lower byte of the wValue variable. This is similar to the wIndex variable that defines the interface for the requested report. 

So I just do the following check before sending the reqested report. 

/* Determine if mouse report was requested (low byte of wValue */
if ( (USB_ControlRequest.wValue & 0xFF) == KEYBOARD_ReportID)


2. What is the correct procedure to send more report thought the same endpoint?   Is the code below correct? 
3. Are there difference between sending reports though the control endpoint (GetReport requests) and the report endpoint?

That might have been a stupid question. There was no reason to drop the USB_Keyboard and USB_Mouse tasks. The only change needed for was to substitute:
Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM) 
Endpoint_SelectEndpoint(MOUSE_IN_EPNUM)

with: 
Endpoint_SelectEndpoint (COMBINED_IN_EPNUM)

Then everything works like a charm..

Cheers
/Morten

Bill Roy

unread,
Jun 5, 2009, 11:24:47 AM6/5/09
to myusb-sup...@googlegroups.com
Morten:

Congratulations.  I'd love to see the code with an eye to using it in the next version of Bitlash-USB.

Dean, I think a working version of this combined client would be a great value-add to the client demo suite.

Best regards,

-br
http://bitlash.net (RC1 is up!)

Morten Enemark Lund

unread,
Jun 8, 2009, 3:40:52 AM6/8/09
to myusb-support-list
Hi Bill

Sorry for the delay. I have been away from work the last days. I have uploaded a version of the combined demo, to the LUFA group. I doesn't contain any of our application specific code, so it should be straight forward. It was originally made for the ATAVRUSBRF01 board, so the demo only uses one button to add data to the different reports. 

I think it is a good idea with a demo that show off some of the more complicated features of LUFA. We better get Dean to rewrite and review the code before it is included. If there is one thing I have learned; it is that code is not necessarily correct just because it works with windows. 

I should mention that I have had some weird problems while testing with USBKEY board. Usually it works fine, but sometimes the HWB causes the board to freeze or reset. I don't know why this happens. It might be a hardware issue, or maybe a combination of several things. 

Best regards
/Morten.


--
Morten Enemark Lund,
Civilingeniør, Medical devices.

TKS A/S, Department of Health Science and Technology, Aalborg University


Dean Camera

unread,
Jun 8, 2009, 4:50:41 AM6/8/09
to LUFA (Formerly MyUSB) Support
Morten,

> I think it is a good idea with a demo that show off some of the more
> complicated features of LUFA. We better get Dean to rewrite and review the
> code before it is included. If there is one thing I have learned; it is that
> code is not necessarily correct just because it works with windows.

Will do - I'll put it on my (growing) TODO list for the next revision.

> I should mention that I have had some weird problems while testing with
> USBKEY board. Usually it works fine, but sometimes the HWB causes the board
> to freeze or reset. I don't know why this happens. It might be a hardware
> issue, or maybe a combination of several things.

That's a hardware bug discovered by another LUFA user. Atmel have
identified a problem with the HWB causing spurious resets, and their
solution is to just disable HWB on the USBKEY. That sucks as it
prevents the user from easily accessing the bootloader, so my advice
is to just not use HWB unless necessary, or at least just live with
the wonky behaviour.

- Dean

On Jun 8, 5:40 pm, Morten Enemark Lund <mel...@gmail.com> wrote:
> Hi Bill
> Sorry for the delay. I have been away from work the last days. I have
> uploaded a version of the combined demo, to the LUFA group. I doesn't
> contain any of our application specific code, so it should be straight
> forward. It was originally made for the ATAVRUSBRF01 board, so the demo only
> uses one button to add data to the different reports.
>
> I think it is a good idea with a demo that show off some of the more
> complicated features of LUFA. We better get Dean to rewrite and review the
> code before it is included. If there is one thing I have learned; it is that
> code is not necessarily correct just because it works with windows.
>
> I should mention that I have had some weird problems while testing with
> USBKEY board. Usually it works fine, but sometimes the HWB causes the board
> to freeze or reset. I don't know why this happens. It might be a hardware
> issue, or maybe a combination of several things.
>
> Best regards
> /Morten.
>
> --
> Morten Enemark Lund,
> Civilingeniør, Medical devices.
> TKS A/S, Department of Health Science and Technology, Aalborg University
>
> On Fri, Jun 5, 2009 at 17:24, Bill Roy <bill...@gmail.com> wrote:
> > Morten:
> > Congratulations.  I'd love to see the code with an eye to using it in the
> > next version of Bitlash-USB.
>
> > Dean, I think a working version of this combined client would be a great
> > value-add to the client demo suite.
>
> > Best regards,
>
> > -br
> >http://bitlash.net(RC1 is up!)
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages