USB NKRO

User avatar
DMA

20 Jun 2016, 04:58

Hi guys, I have a question: Why everyone (well.. probably not _everyone_, but I have yet to see a counterexample yet) uses key bitmaps for NKRO interface?
120 keys better than 62, I get it, but it's 120 _fixed_ keys, you need to define them at enumeration.
One can easily put modifier bitmap + 8 LEDs + 62 scancodes into USB 2.0 fulls peed interrupt packet - why I don't see such implementations?

One has to try extra hard to press 62 keys at once - much less 120. Why not use more flexible approach? Is there something which I don't know and it only reveals itself in testing?

You can also probably put keyboard + system + consumer pages into one report - USAGE_MINIMUM and USAGE_MAXIMUM can span usage pages, HID spec says - but this is yet to be tested. If it works though - one report to rule them all, should simplify a lot of things.

User avatar
HaaTa
Master Kiibohd Hunter

20 Jun 2016, 05:21

So, yes, I agree (I've also tried doing selective sending of portions of the hid descriptor to optimize the actual data transfer).

Unfortunately, the main reason why not a lot of other descriptors have been tried...OS compatibility. Linux, Windows and Mac all have their own unique non-conforming HID stack tweaks.

However! Please don't let this stop you, more efficient USB is better USB :D

Some of my compatibility notes are here -> https://github.com/kiibohd/controller/b ... esc.c#L174

User avatar
DMA

20 Jun 2016, 07:13

What are ISO bksp/del and \| bugs?
(also this doesn't make USB any more efficient - just simplifies descriptors a bit and allows boot keyboard to use basically the same protocol, just shorter).

Well, it looks like I'll experience those firsthand very soon :)

HuBandiT

20 Jun 2016, 08:13

DMA wrote: Hi guys, I have a question: Why everyone (well.. probably not _everyone_, but I have yet to see a counterexample yet) uses key bitmaps for NKRO interface?
120 keys better than 62, I get it, but it's 120 _fixed_ keys, you need to define them at enumeration.
One can easily put modifier bitmap + 8 LEDs + 62 scancodes into USB 2.0 fulls peed interrupt packet - why I don't see such implementations?

One has to try extra hard to press 62 keys at once - much less 120. Why not use more flexible approach? Is there something which I don't know and it only reveals itself in testing?

You can also probably put keyboard + system + consumer pages into one report - USAGE_MINIMUM and USAGE_MAXIMUM can span usage pages, HID spec says - but this is yet to be tested. If it works though - one report to rule them all, should simplify a lot of things.
well, technically, as far as I can recall from my memory, scan codes in USB are 16 bits long and not 8 (even though codes E8-FFFF are reserved); so if you really did not want to limit your scan codes at enumeration to a fixed set, you would have to allow for the entire range, and in that case you could only fit about 30 keys into a report. And as a purist's argument, that is _not_ full NKRO. :) However, if I understand the logic correctly, in theory you could go with a relative report for the key states, in which case you would in effect only report keys that have changed state since the last report. This would limit you to about 60/30 key _changes_ per report, and thereby enable full NKRO, albeit only with a slight delay for cases where the user presses/releases more than about 60/30 keys in one report period (1 ms for the most common full-speed case).

And even that without unambiguously reporting key press/release order - which would necessitate reporting only _one_ key change per report.

These limits however only hold for single-transaction full-speed (12 Mbits/s; interestingly, this part of the standard only mentions low-speed and high-speed, with a speed/capacity ratio of 1:8, and 1ms frame rate for high-speed; whereas the actual USB 2.0 speeds are low-speed at 1.5 Mbits/s, full-speed at 12 Mbits/s and high-speed at 480 Mbits/s, so I think in this aspect the standard as worded is in error); but the standard allows you to go send longer, multiple-transaction reports; so you could, in theory, define and send a longer array report with enough slots for all keys, which will then get sent over consecutive frames (about 4 frames if you decide to limit things to 8 bit scan codes), and provide you with full NKRO and (limited - to 8 bits) flexibility in reported scan codes. Of course, then, to avoid unnecessary delay/latency for the common case of less than about 60 keys being pressed, you would define multiple reports to allow for a shorter, single-transaction report as well; note however, that in this case you will lose a byte as for each report you will have to use the first byte to specify which of the enumerated reports you are sending this time. Extending the scenario for the fully flexible 16 bit scan code case is left as an exercise to the reader, but it probably would necessitate at least high-speed, because a 1ms frame rate with 64 byte reports (31 scan codes per report) would necessitate about 2114 ms per full report, which is a longer latency than most users would probably want to put up with. Plus, to unambiguously report key press/release order in this case as well, you would only, again, report _one_ key change per report. So reporting each keypress (key down and then eventually key up) would require a little over four seconds.

So clearly, you should switch to relative reports instead. And in fact, since you only ever want to report one key change per report, this would also mean an array report with one single slot would perfectly suffice. Which also makes full flexibility with 16 bit scan codes quite feasible, as your report would be a mere one scan code (1 or 2 bytes) long.

Phew.

Back to your question of why people go with the bitmap report: as I specifically wanted a 105-key ISO keyboard, where the scan codes of all the keys are well-defined, I went with the bitmap for conceptual simplicity.

Also, aren't LEDs sent by host to keyboard, and not by keyboard to host?

User avatar
DMA

20 Jun 2016, 08:22

HuBandiT wrote: So clearly, you should switch to relative reports instead. And in fact, since you only ever want to report one key change per report, this would also mean an array report with one single slot would perfectly suffice. Which also makes full flexibility with 16 bit scan codes quite feasible, as your report would be a mere one scan code (1 or 2 bytes) long.
How do you signal which key is released then? Autorepeat is handled on the host side, it needs to know which keys are pressed right now.
HuBandiT wrote: Also, aren't LEDs sent by host to keyboard, and not by keyboard to host?
[/quote]
They are. Can be done thru separate interface though, spec doesn't prevent that. Boot mode support will have to do with single report though - one can say "fuck LEDs, it's boot time, you don't need that", and one will be right :)

HuBandiT

20 Jun 2016, 08:53

DMA wrote:
HuBandiT wrote: So clearly, you should switch to relative reports instead. And in fact, since you only ever want to report one key change per report, this would also mean an array report with one single slot would perfectly suffice. Which also makes full flexibility with 16 bit scan codes quite feasible, as your report would be a mere one scan code (1 or 2 bytes) long.
How do you signal which key is released then? Autorepeat is handled on the host side, it needs to know which keys are pressed right now.
Well, I am only theorizing this from the logic of the specification (and the whole thing is a big tongue-in-cheek), but: with relative records, you would send a zero (empty slot/no scancode) while there is no change in key states, and when there is a change in key states, you would send the scan code for the key that changed state. (You might also need to report the direction of change of the key state in a second field - I did not actually read the logic of relative fields combined with arrays.) The host would then have all information it needs to do a full bookkeeping on the state of each key in memory, and then could implement autorepeat on top of that. I think it is only the simplified boot protocol processing implementation in the host that is kinda expected to abuse the keyboard's report rate functionality to do a sort of cooperative-autorepeat - logic would dictate that full blown implementations - as you write above - decouple all concern of autorepeat from the keyboard, and merely seek to receive just enough information to keep an always up-to-date state for each key in the host's memory.

But again, this is only theory on my part, and maybe the standard does not actually allow this. (Let alone to what extent - if any - actual implementations would be able to cope with this.)
DMA wrote:
HuBandiT wrote: Also, aren't LEDs sent by host to keyboard, and not by keyboard to host?
They are. Can be done thru separate interface though, spec doesn't prevent that. Boot mode support will have to do with single report though - one can say "fuck LEDs, it's boot time, you don't need that", and one will be right :)
My point was: don't count the LEDs taking up space in the key report going from the keyboard to the host, because LED information will never be in that report, since LED information is only ever going from host to keyboard. And it does work in boot mode already, does it not?

Post Reply

Return to “Workshop”