USB HID Descriptor (V-USB)

Gast #1724821
Lesenswert?

Einen wunderschönen guten Abend! :)
Ich experimentiere zur Zeit ein wenig am V-USB Beispielprojekt 
"HID-Keys" (http://www.obdev.at/products/vusb/hidkeys.html) herum. Ziel 
ist, die Mediatasten moderner USB-Tastaturen (Play, Pause, ...) 
hinzukriegen.
Mein Descriptor, von dem ich mir erhoffe, dass er einfach auf den 
angestrebten Zweck umzuschreiben ist, sieht jetzt wie folgt aus (und 
kann für die üblichen Lettern/Ziffern benutzt werden, Shift ist für mich 
irrelevant)
1
char usbHidReportDescriptor[35] = {
2
    0x05, 0x0c,                    // USAGE_PAGE (Consumer Devices)
3
    0x09, 0x01,                    // USAGE (Consumer Control)
4
    0xa1, 0x01,                    // COLLECTION (Application)
5
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
6
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
7
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
8
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
9
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
10
    0x75, 0x08,                    //   REPORT_SIZE (8)
11
    0x95, 0x01,                    //   REPORT_COUNT (1)
12
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
13

14
    0x09, 0x00,                    //   USAGE (Unassigned)
15
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
16
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
17
    0x75, 0x01,                    //   REPORT_SIZE (1)
18
    0x95, 0x00,                    //   REPORT_COUNT (0)
19
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
20
    0xc0                           // END_COLLECTION
21
};
Was mir einiges an Rumgewurschtle bereitet hat, ist der zweite Teil, der 
ja eigentlich 0 mal ein Bit unbelegten Inhaltes ankündigt, aus mir 
unbekanntem Grunde jedoch unerlässlich ist.
Auf dieser (funktionierenden) Basis dann Versuch zwei mit 
Mediafunktionen:
1
char usbHidReportDescriptor[43] = {
2
    0x05, 0x0c,                    // USAGE_PAGE (Consumer Devices)
3
    0x09, 0x01,                    // USAGE (Consumer Control)
4
    0xa1, 0x01,                    // COLLECTION (Application)
5
    0x05, 0x0c,                    //   USAGE_PAGE (Consumer Devices)
6
    0x09, 0xb0,                    //   USAGE (Play)
7
    0x09, 0xb1,                    //   USAGE (Pause)
8
    0x09, 0xb5,                    //   USAGE (Scan Next Track)
9
    0x09, 0xb6,                    //   USAGE (Scan Previous Track)
10
    0x09, 0xb7,                    //   USAGE (Stop)
11
    0x09, 0xe2,                    //   USAGE (Mute)
12
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
13
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
14
    0x75, 0x01,                    //   REPORT_SIZE (1)
15
    0x95, 0x06,                    //   REPORT_COUNT (6)
16
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
17
    0x09, 0x00,                    //   USAGE (Unassigned)
18
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
19
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
20
    0x75, 0x01,                    //   REPORT_SIZE (1)
21
    0x95, 0x02,                    //   REPORT_COUNT (2)
22
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
23
    0xc0                           // END_COLLECTION
24
};
XP gibt mir dafür ein "Gerät konnte nicht gestartet werden", ich kann 
aber nicht nachvollziehen, was das Problem sein könnte.

Ich hoffe auf Anregungen und danke euch vielmals fürs Lesen und Helfen!
Andreas
Gast #1724844
Lesenswert?

Ich glaub nicht daß der HID Descriptor noch korrekt ist mit den 
zusätzlichen USAGE einträgen. Wenn du Media Keys übertragen willst, 
passiert das innerhalb eines Reports den du abschickst ( der mit 
modifier keys an 1. stelle und dann folgend den pressed keys. 8byte groß 
wie in deinem ersten beispiel angegeben) Die Hex-Werte für die 
speziellen keys müßten auf der usb.org seite gelistet sein.
#1725901
Lesenswert?

Meinst du so?
1
char usbHidReportDescriptor[36] = {
2
    0x05, 0x0c,                    // USAGE_PAGE (Consumer Devices)
3
    0x09, 0x01,                    // USAGE (Consumer Control)
4
    0xa1, 0x01,                    // COLLECTION (Application)
5
    0x05, 0x0c,                    //   USAGE_PAGE (Consumer Devices)
6
    0x19, 0x00,                    //   USAGE_MINIMUM (Unassigned)
7
    0x29, 0xb7,                    //   USAGE_MAXIMUM (Stop)
8
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
9
    0x26, 0xb7, 0x00,              //   LOGICAL_MAXIMUM (183)
10
    0x75, 0x08,                    //   REPORT_SIZE (8)
11
    0x95, 0x01,                    //   REPORT_COUNT (1)
12
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
13
    0x09, 0x00,                    //   USAGE (Unassigned)
14
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
15
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
16
    0x75, 0x01,                    //   REPORT_SIZE (1)
17
    0x95, 0x00,                    //   REPORT_COUNT (0)
18
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
19
    0xc0                           // END_COLLECTION
20
};
Klappt leider auch nicht :(
#1726147
Lesenswert?

Hallo Andreas S.,

versuchs mal hiermit:
1
//Class specific descriptor - HID Keyboard
2
char usbHidReportDescriptor[63] = {
3
    0x05, 0x01,    // USAGE_PAGE (Generic Desktop)
4
    0x09, 0x06,     // USAGE (Keyboard)
5
    0xa1, 0x01,     // COLLECTION (Application)
6
    0x05, 0x07,     //   USAGE_PAGE (Keyboard)
7
    0x19, 0xe0,     //   USAGE_MINIMUM (Keyboard LeftControl)
8
    0x29, 0xe7,     //   USAGE_MAXIMUM (Keyboard Right GUI)
9
    0x15, 0x00,     //   LOGICAL_MINIMUM (0)
10
    0x25, 0x01,     //   LOGICAL_MAXIMUM (1)
11
    0x75, 0x01,     //   REPORT_SIZE (1)
12
    0x95, 0x08,     //   REPORT_COUNT (8)
13
    0x81, 0x02,     //   INPUT (Data,Var,Abs)
14
    0x95, 0x01,     //   REPORT_COUNT (1)
15
    0x75, 0x08,     //   REPORT_SIZE (8)
16
    0x81, 0x03,     //   INPUT (Cnst,Var,Abs)
17
    0x95, 0x05,     //   REPORT_COUNT (5)
18
    0x75, 0x01,     //   REPORT_SIZE (1)
19
    0x05, 0x08,     //   USAGE_PAGE (LEDs)
20
    0x19, 0x01,     //   USAGE_MINIMUM (Num Lock)
21
    0x29, 0x05,     //   USAGE_MAXIMUM (Kana)
22
    0x91, 0x02,     //   OUTPUT (Data,Var,Abs)
23
    0x95, 0x01,     //   REPORT_COUNT (1)
24
    0x75, 0x03,     //   REPORT_SIZE (3)
25
    0x91, 0x03,     //   OUTPUT (Cnst,Var,Abs)
26
    0x95, 0x06,     //   REPORT_COUNT (6)
27
    0x75, 0x08,     //   REPORT_SIZE (8)
28
    0x15, 0x00,     //   LOGICAL_MINIMUM (0)
29
    0x25, 0x65,     //   LOGICAL_MAXIMUM (101)
30
    0x05, 0x07,     //   USAGE_PAGE (Keyboard)
31
    0x19, 0x00,     //   USAGE_MINIMUM (Reserved (no event indicated))
32
    0x29, 0x65,     //   USAGE_MAXIMUM (Keyboard Application)
33
    0x81, 0x00,     //   INPUT (Data,Ary,Abs)
34
    0xc0            // End Collection
35
};

Die zugehörigen Usage ID's findest Du in 'Hut1_11.pdf' (S. 53 ff) bei 
usb.org.

Gruß Ralf
#1727406
Lesenswert?

Moin,
Der Descriptor funktioniert zwar für ein Keyboard, jedoch nicht für die 
gewünschten Sondertasten :(
"LOGICAL_MAXIMUM" und "USAGE_MAXIMUM" habe ich auf 0x7f (Usage ID für 
"Mute" aus der genannten Tabelle, danke!) angehoben. Stelle ich nun 
"0x7f" zum Abholen bereit tut sich leider nichts.

Könnte das u.U. damit zusammenhängen, dass in der Tabelle rechts bei den 
Usages für Play, Pause, Mute usw. nur bei "UNIX" ein Haken ist, nicht 
aber bei "PC-AT" ? USBLyzer zeigt mir beim entsprechenden Tastendruck 
nämlich auch an, dass 0x7f ("Mute") bzw. einer der anderen tabellierten 
Werte abgeholt wurde. Mag sich vielleicht jemand die Trial runterladen 
und mir das Protokoll nach Druck der Mediatasten zur Verfügung stellen?
#1939357
Lesenswert?

Du musst dir doch einfach nur deinen keyReport anpassen. Bei mir sieht 
das z.B. so aus:
1
#define MOD_CONTROL_LEFT    (1<<0)
2
#define MOD_SHIFT_LEFT      (1<<1)
3
#define MOD_ALT_LEFT        (1<<2)
4
#define MOD_GUI_LEFT        (1<<3)
5
#define MOD_CONTROL_RIGHT   (1<<4)
6
#define MOD_SHIFT_RIGHT     (1<<5)
7
#define MOD_ALT_RIGHT       (1<<6)
8
#define MOD_GUI_RIGHT       (1<<7)
9

10
#define KEY_A       4
11
#define KEY_B       5
12

13
....
14

15
#define KEY_X       27
16
#define KEY_Y       28
17
#define KEY_Z       29
18
#define KEY_1       30
19

20
...
21

22
#define KEY_9       38
23
#define KEY_0       39
24

25
#define KEY_ENTER   40
26
#define KEY_SPACE   44
27
#define KEY_RARROW  79
28
#define KEY_LARROW  80
29
#define KEY_DOWN  81
30
#define KEY_UP    82
31

32

33
static const uchar  keyReport[NUM_KEYS + 1][2] PROGMEM = {
34
/* none */  {0, 0},                     /* no key pressed */
35
/*  1 */    {MOD_CONTROL_RIGHT, KEY_RARROW},//hoch
36
/*  2 */    {MOD_CONTROL_RIGHT, KEY_LARROW},//runter
37
/*  3 */    {MOD_SHIFT_RIGHT, KEY_LARROW},  //links
38
/*  4 */    {MOD_SHIFT_RIGHT, KEY_RARROW},  //rechts
39
/*  5 */    {0, KEY_ENTER},          //OK
40
/*  6 */    {0, KEY_N},            //CH+
41
/*  7 */    {0, KEY_P},            //CH-
42
/*  8 */    {MOD_CONTROL_LEFT, KEY_UP},    //Vol+
43
/*  9 */    {MOD_CONTROL_LEFT, KEY_DOWN},  //Vol-
44
/* 10 */    {0, KEY_P},            //rewind
45
/* 11 */    {0, KEY_SPACE},          //play
46
/* 12 */    {0, KEY_N},            //forward
47
/* 13 */    {0, KEY_S},            //stop
48
/* 14 */    {0, KEY_SPACE},          //pause
49
/* 15 */    {MOD_ALT_RIGHT, KEY_D},      //videotext, DualView
50
/* 16 */    {MOD_ALT_LEFT, KEY_F4},      //ausschalten
51

52
};

Soll heißen, deinem play etc ist ein Hexwert zugeordnet den du senden 
musst. Schau dazu mal in dem angehängten PDF ab Seite 53 nach dem 
entsprechenden Wert (ist ja alles  standardisiert).
Stop, Mute etc. stehen da alle drin.
#1939397
Lesenswert?

Danke dir :-)
Dass der keyReport ebenfalls angepasst werden muss ist mir klar, Problem 
ist wie gesagt, dass eben die übermittelten "Play", "Pause" und wie sie 
alle heißen mögen keinen Effekt haben. Dein keyReport ist leider nur die 
eine für mich provisorische Lösung, die ich auch schon gefunden habe. 
Problem daran ist, dass sich bspw. mit CTRL-Up nur bestimmte Software 
steuern lässt. (Ich hoffe, ich liege nicht grottenfalsch und selbiges 
gilt nicht etwa auch für die Mediatasten einer USB-Tastatur)
Gast #2141992
Lesenswert?

Hallo,
ich mache gerade etwas ähnliches. ich möchte ein kleines Keypad 
zusammenstellen das mir Klammern und andere Operatoren leichter 
zugänglich macht. Ich verstehe soweit eigentlich den Code des VUSB 
Projektes nur die Funktion keyreport ist mir ein Rätsel. Was passiert 
mit der Usage-ID wenn ich einen MOD_KEY voranstelle. Im HID Usage Table 
sind ja für jeden erdenklichen Key die werte aufgelistet. ich könnte 
also immer
{0, KEY_XY}
in der keyreport Funktion schreiben?
Also direkt ohne MOD KEYS? Wie gesagt verstehe lediglich diese Funktion 
nicht so ganz, wäre toll wenn mich jemand erleuchten könnte.
Gast #2574194
Lesenswert?

Mir ist bewusst, dass der Thread schon lange unbeobachtet blieb, doch da 
ich mich selbst auf der Suche nach den Media Funktionen befand und eine 
lösung dazu zusammenstellen konnte.
Der Descriptor hat bei mir in diesem Falle folgende Struktur:
1
PROGMEM char usbHidReportDescriptor[65] = { // USB report descriptor
2
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
3
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
4
    0xa1, 0x01,                    // COLLECTION (Application)
5
    0x85, 0x01,                    //   REPORT_ID (1)
6
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
7
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
8
    0x75, 0x08,                    //   REPORT_SIZE (8)
9
    0x95, 0x0a,                    //   REPORT_COUNT (10)
10
    0x09, 0x00,                    //   USAGE (Undefined)
11
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
12
    0xc0,                          // END_COLLECTION
13

14
    0x05, 0x0c,                    // USAGE_PAGE (Consumer)
15
    0x09, 0x01,                    // USAGE (Consumer Control)
16
    0xa1, 0x01,                    // COLLECTION (Application)
17
    0x85, 0x02,                    //   REPORT_ID (2)
18
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
19
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
20
    0x09, 0xe9,                    //   USAGE (Volume Increment)
21
    0x09, 0xea,                    //   USAGE (Volume Decrement)
22
    0x75, 0x01,                    //   REPORT_SIZE  (1)
23
    0x95, 0x02,                    //   REPORT_COUNT (2)
24
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
25
    0x09, 0xe2,                    //   USAGE (Mute)
26
    0x09, 0xb5,                    //   USAGE (Scan Next Track)
27
    0x09, 0xb6,                    //   USAGE (Scan Previous Track)
28
    0x09, 0xb7,                    //   USAGE (Stop)
29
    0x09, 0xcd,                    //   USAGE (Play/Pause)
30
    0x95, 0x05,                    //   REPORT_COUNT (5)
31
    0x81, 0x06,                    //   INPUT (Data,Var,Rel)
32
    0x95, 0x01,                    //   REPORT_COUNT (1)
33
    0x81, 0x01,                    //   INPUT (Constant)
34
    0xc0                           // END_COLLECTION
35
};
Die Feature ID ist hier mal nicht von Bedeutung, ich nutze sie als Setup 
Schnittstelle. Von Interesse ist die Consumer Page.
Dem Host muss man demnach einen Datenblock von 2 Bytes senden. Das erste 
Byte enthält die Report ID und das zweite dann bitweise die Keys...
[{2, 0b00100000} würde die Mute Funktion toggeln]
Wie der Report zu übermitteln ist, sollte jedem aus den Comunity 
Projekten auf www.obdev.at bekannt sein. Dennoch führe ich das zu 
Sicherheit nochmal auf:
1
uchar  usbFunctionSetup (uchar data[8])
2
{
3
    usbRequest_t    *rq = (void *)data;
4

5
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS)
6
    {
7
        if(rq->bRequest == USBRQ_HID_GET_REPORT)
8
        {
9
            usbMsgPtr = BUFFER;
10
            return 2;
11
        }
12

13
...
14

15
}
Als Reaktion, falls der Report explizit gefordert wird. Dies kommt kaum 
bis überhaupt nicht vor, doch schaden kanns nicht.

Im main loop muss man nun nur noch die Reports selbst senden, wenn man 
die Änderung eines Keys vermelden möchte.
1
int  main (void)
2
{
3

4
...
5

6
    while(42)
7
    {
8

9
...
10

11
        usbPoll();
12

13
...
14

15
        if(KEY_CHANGED && usbInterruptIsReady())
16
        {
17
            usbSetInterrupt(BUFFER, 2);
18
        }
19
    }
20
    return 0;
21
}
Ich hoffe das dies irgendwem helfen kann, denn ich persönlich war 
zwischenzeitlich von der Suche durchaus frustriert.


Viel Spass weiterhin beim Werkeln...

Nicki
#2692263
Lesenswert?

Hallo Kurt,
wie du vermutlich bemerkt hast, hab ich strukturelle Einzelheiten aus 
HID-Keys übernommen.
In diesem jenen Projekt wird folgende Funktion zum bilden des Reports 
aufgerufen:
1
static uchar    reportBuffer[2];    /* buffer for HID reports */
2

3
...
4

5
static void buildReport(uchar key)
6
{
7
/* This (not so elegant) cast saves us 10 bytes of program memory */
8
    *(int *)reportBuffer = pgm_read_word(keyReport[key]);
9
}

Hier wird ja nur für den Inhalt des Buffers auf einen 
Programmspeicherbereich bestehend aus einem Word verwiesen. An diesem 
Punkt musst du dann Eingreifen und den Inhalt, wie es der HID Treiber 
wünscht, beschreiben. Das erste Byte muss also der Report ID 
entsprechen, die in dem obigen Descriptor vorliegt (bzw. welche auch 
immer du definierst), und das zweite Byte enthält dann den aktuellen 
status der Keys.
Im Descriptor werden hintereinander die Funktionen, welche du 
beeinflussen möchtest, aufgelistet. Diese Reihenfolge muss bei der 
Statusübertragung eingehalten werden, die mit dem niedrigsten Bit 
beginnt.

Ich geb dir im folgenden mal eine Beispiel, bei der die Mute Funktion 
gesendet wird. Bedenke, dass dies nur symbolisch ist, letzten Endes 
musst du das an deine Hardware und deine genaue Funktionsvorstellung 
anpassen.
1
...
2
static uchar    reportBuffer[2];    /* buffer for HID reports */
3

4
#define     KEY_VOLUME_INC      0x01
5
#define     KEY_VOLUME_DEC      0x02
6
#define     KEY_MUTE            0x04
7

8
...
9

10
PROGMEM char usbHidReportDescriptor[65] = { // USB report descriptor
11
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
12
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
13
    0xa1, 0x01,                    // COLLECTION (Application)
14
    0x85, 0x01,                    //   REPORT_ID (1)
15
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
16
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
17
    0x75, 0x08,                    //   REPORT_SIZE (8)
18
    0x95, 0x0a,                    //   REPORT_COUNT (10)
19
    0x09, 0x00,                    //   USAGE (Undefined)
20
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
21
    0xc0,                          // END_COLLECTION
22

23
    0x05, 0x0c,                    // USAGE_PAGE (Consumer)
24
    0x09, 0x01,                    // USAGE (Consumer Control)
25
    0xa1, 0x01,                    // COLLECTION (Application)
26
    0x85, 0x02,                    //   REPORT_ID (2)
27
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
28
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
29
    0x09, 0xe9,                    //   USAGE (Volume Increment)
30
    0x09, 0xea,                    //   USAGE (Volume Decrement)
31
    0x75, 0x01,                    //   REPORT_SIZE  (1)
32
    0x95, 0x02,                    //   REPORT_COUNT (2)
33
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
34
    0x09, 0xe2,                    //   USAGE (Mute)
35
    0x09, 0xb5,                    //   USAGE (Scan Next Track)
36
    0x09, 0xb6,                    //   USAGE (Scan Previous Track)
37
    0x09, 0xb7,                    //   USAGE (Stop)
38
    0x09, 0xcd,                    //   USAGE (Play/Pause)
39
    0x95, 0x05,                    //   REPORT_COUNT (5)
40
    0x81, 0x06,                    //   INPUT (Data,Var,Rel)
41
    0x95, 0x01,                    //   REPORT_COUNT (1)
42
    0x81, 0x01,                    //   INPUT (Constant)
43
    0xc0                           // END_COLLECTION
44
};
45

46
...
47

48
static void buildReport()    // Das Argument aus dem Beispielproject brauchen wir nicht,
49
{                            // da wir den Inhalt kennen.
50
    reportBuffer[0] = 0x02;  // Inhalt gehört zur Report ID 2 (Consumer Page)
51
    if (PIND & (1 << PIN0))  // Mute Taste abfragen (Debounce soll hierbei nicht interessieren)
52
        reportBuffer[1] |= (1 << KEY_MUTE);  // Mute wird als aktiv beschrieben
53
    else
54
        reportBuffer[1] &= ~(1 << KEY_MUTE); // Mute wird als inaktiv beschrieben
55
}
56

57
...

Im Projekt HID-Keys wird im mainloop im Zuge der IdleRate zyklisch der 
Report gebildet und geschickt, somit könnte dies theoretisch so 
eingebunden werden. Allerdings wird der Fall, dass der Report zur ID 1 
gewünscht ist gänzlich ignoriert, da wir das Highbyte permament auf 2 
setzen...

Desweiteren muss man sich zu den Benutzungstypen der einzelnen Tasten 
genau erkundigen. Mute als Beispiel wird vom UsageType als OOC (On/Off 
Control) angegeben, was bedeutet, dass man den absoluten Wert sendet. 
Bei OSC (One Shot Control) andererseits würde ein Wechsel vom Wert 0 zu 
1 triggern, also sowohl aktivieren als auch deaktivieren.

Mehr dazu im Abschnitt "15 Consumer Page (0x0C)" (Seite 75 ff) der "USB 
HID Usage Tables".
http://www.usb.org/developers/devclass_docs/Hut1_11.pdf
Die Funktionstypen findest du in der gleichen pdf im Abschnitt "3.4.1 
Usage Types (Controls)" (Seite 18).

Ich hoffe das ist dir eine Hilfe und stellt sich nicht als verwirrend 
dar.

Für Fragen steh ich selbstverständlich auch weiter zur Verfügung ;)


Greez, Nicki
Gast #3617126
Lesenswert?

Da ich mich gerade mit dem gleichen beschäftige, wollt ich hier noch 
meine Lösung posten. Ich brauchte die Mute-Taste für ein vusb projekt. 
Die Lösung hat jedoch einen Nachteil: Sie funktioniert bei mir nur unter 
Linux. Windows erkennt zwar das HID-Gerät und "normale" Tasten 
funktionieren, jedoch die Mute Taste nicht.

Ich nutze folgenden Report:
1
const char usbHidReportDescriptor[36] PROGMEM = { /* USB report descriptor */
2
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
3
    0x09, 0x06,                    // USAGE (Keyboard)
4
    0xa1, 0x01,                    // COLLECTION (Application)
5
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
6
    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
7
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
8
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
9
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
10
    0x75, 0x01,                    //   REPORT_SIZE (1)
11
    0x95, 0x08,                    //   REPORT_COUNT (8)
12
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
13
    0x95, 0x01,                    //   REPORT_COUNT (1)
14
    0x75, 0x08,                    //   REPORT_SIZE (8)
15
    0x26, 0xe7, 0x00,              //   LOGICAL_MAXIMUM (231)
16
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
17
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
18
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
19
    0xc0                           // END_COLLECTION
20
    };
Ich habe dazu einfach den Report Descriptor aus dem HID Beispiel in das 
HID Descriptor Tool abgetippt und dann im zweiten Block die Felder 
Logical Maximum und Usage Maximum auf einen höheren Wert gesetzt.

Wenn ich nun {0x00,0x7f} als report sende, funktioniert der Mute.

MfG
  Micha
#3960460
Lesenswert?

Well, that is strange.
I got it all working on the ATmega48/88, which are both basically the 
same MCU as yours, only with less memory.
There must be something wrong with your hardware setup (chosen pins, 
pullup res, ...) or the USB firmware configuration (more likely).
I suggest you have a look into that because it should work, of that I am 
certain.

Good luck ;)
Gast #3960621
Lesenswert?

Nicholas F. ,This example works!! 
http://www.obdev.at/products/vusb/hidkeys.html

But this example does not work(((
1
...
2
static uchar    reportBuffer[2];    /* buffer for HID reports */
3

4
#define     KEY_VOLUME_INC      0x01
5
#define     KEY_VOLUME_DEC      0x02
6
#define     KEY_MUTE            0x04
7

8
...
9

10
PROGMEM char usbHidReportDescriptor[65] = { // USB report descriptor
11
    0x06, 0x00, 0xff,              // USAGE_PAGE (Generic Desktop)
12
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
13
    0xa1, 0x01,                    // COLLECTION (Application)
14
    0x85, 0x01,                    //   REPORT_ID (1)
15
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
16
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
17
    0x75, 0x08,                    //   REPORT_SIZE (8)
18
    0x95, 0x0a,                    //   REPORT_COUNT (10)
19
    0x09, 0x00,                    //   USAGE (Undefined)
20
    0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
21
    0xc0,                          // END_COLLECTION
22

23
    0x05, 0x0c,                    // USAGE_PAGE (Consumer)
24
    0x09, 0x01,                    // USAGE (Consumer Control)
25
    0xa1, 0x01,                    // COLLECTION (Application)
26
    0x85, 0x02,                    //   REPORT_ID (2)
27
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
28
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
29
    0x09, 0xe9,                    //   USAGE (Volume Increment)
30
    0x09, 0xea,                    //   USAGE (Volume Decrement)
31
    0x75, 0x01,                    //   REPORT_SIZE  (1)
32
    0x95, 0x02,                    //   REPORT_COUNT (2)
33
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
34
    0x09, 0xe2,                    //   USAGE (Mute)
35
    0x09, 0xb5,                    //   USAGE (Scan Next Track)
36
    0x09, 0xb6,                    //   USAGE (Scan Previous Track)
37
    0x09, 0xb7,                    //   USAGE (Stop)
38
    0x09, 0xcd,                    //   USAGE (Play/Pause)
39
    0x95, 0x05,                    //   REPORT_COUNT (5)
40
    0x81, 0x06,                    //   INPUT (Data,Var,Rel)
41
    0x95, 0x01,                    //   REPORT_COUNT (1)
42
    0x81, 0x01,                    //   INPUT (Constant)
43
    0xc0                           // END_COLLECTION
44
};
45

46
...
47

48
static void buildReport()    // Das Argument aus dem Beispielproject brauchen wir nicht,
49
{                            // da wir den Inhalt kennen.
50
    reportBuffer[0] = 0x02;  // Inhalt gehört zur Report ID 2 (Consumer Page)
51
    if (PIND & (1 << PIN0))  // Mute Taste abfragen (Debounce soll hierbei nicht interessieren)
52
        reportBuffer[1] |= (1 << KEY_MUTE);  // Mute wird als aktiv beschrieben
53
    else
54
        reportBuffer[1] &= ~(1 << KEY_MUTE); // Mute wird als inaktiv beschrieben
55
}
56

57
...


whether to make changes to makefile's ?
#3961032
Lesenswert?

Well, my code was based on "hidkeys" but does not have a lot in common 
with it anymore and is way too packed with other stuff to be a good 
reference.

But you wrote that "hidkeys" worked on your controller and I assume that 
you know your MCU and all the code beside V-USB (regarding IO, change of 
key state, ...).

So if "not work" means the device can't be recognized by the USB driver, 
my wild guess would be, that the HID descriptor length in "usbconfig.h" 
was not adjusted...
1
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    65

If that is not your the problem, (maybe) I could put a sample file 
together.
But I would not be able to test it on any hardware.
Gast #3992923
Lesenswert?

Nicholas F,

avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega8 -DF_CPU=12000000L  -c 
main.c -o main.o
main.c:33:14: error: conflicting types for ‘usbDescriptorHidReport’
usbdrv/usbdrv.h:477:6: note: previous declaration of 
‘usbDescriptorHidReport’ was here
main.c: In function ‘buildReport’:
main.c:72:5: error: ‘USB_BUF_TX’ undeclared (first use in this function)
main.c:72:5: note: each undeclared identifier is reported only once for 
each function it appears in
main.c:73:21: error: ‘KEY_VALUES’ undeclared (first use in this 
function)
main.c:74:5: warning: ‘return’ with a value, in function returning void
main.c: In function ‘usbFunctionSetup’:
main.c:81:17: error: ‘USB_BUF_TX’ undeclared (first use in this 
function)
main.c:87:13: error: void value not ignored as it ought to be
main.c: In function ‘main’:
main.c:117:5: warning: implicit declaration of function ‘hardwareInit’
main.c:132:11: error: ‘KEY_VALUES’ undeclared (first use in this 
function)
main.c:136:5: warning: implicit declaration of function ‘_delay_ms’
main.c:151:29: error: ‘USB_BUF_TX’ undeclared (first use in this 
function)
main.c:151:13: warning: implicit declaration of function 
‘usbBuildReport’
main.c:114:10: warning: unused variable ‘idleCounter’

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren