Forum: Compiler & IDEs USB HID Descriptor (V-USB)


von Andreas S (Gast)


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

von enwo (Gast)


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.

von Andreas S. (drohgebaerde)


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 :(

von Potter S. (potter68)


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

von Andreas S. (drohgebaerde)


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?

von Info (Gast)


Lesenswert?

Bist du schon weitergekommen?

von Andreas S. (drohgebaerde)


Lesenswert?

Nein, das Projekt habe ich bisher zurückgestellt. Wenn immer die 
Möglichkeit bestand, mal bei einem bekannten den USBLyzer laufen zu 
lassen, habe ich's anscheinend vergessen :-/

Bedarf an Logs oder Vorschlägen besteht aber immer noch!

Andreas

von Remote O. (remote1)


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.

von Andreas S. (drohgebaerde)


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)

von Info (Gast)


Lesenswert?

Du hast den Anhang vergessen, es würde mich interessieren!

von Remote O. (remote1)


Angehängte Dateien:

Lesenswert?

Hier noch mal der Anhang.
Schau mal da vorbei: http://www.usb.org/developers/hidpage/
interessant sollte das Tool "HID Descriptor Tool" bzw. "HIDView" sein

USB View zeigt die evtl. auch den Descriptor deiner Tastatur:
http://www.ftdichip.com/Support/Utilities.htm

von sven (Gast)


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.

von Andreas S. (drohgebaerde)


Lesenswert?

Tag,
Die "Mod Keys" sind Tasten à la Shift, Ctrl etc.
Wenn du die "Mod Keys" grundsätzlich nicht brauchst, stellst du entweder 
jeweils eine 0 vor (siehe dein Post) oder reduzierst die Zellen des 
keyReport auf jeweils ein Byte (KEY_XY). Der Descriptor muss dann 
entsprechend angepasst werden.

von Nicholas Feix (Gast)


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

von Andreas S. (drohgebaerde)


Lesenswert?

Ich bin begeistert! Danke Nicholas, das sind tolle Neuigkeiten! :-) Ich 
habe allzu häufig mit Wehmut das verwaiste Eclipse-Projekt entdeckt... 
womit nun auch der arbeitsfreie Teil der Semesterferien seine Erfüllung 
finden wird.

Wirklich, vielen herzlichen Dank!

von Nicholas F. (snip3rnick)


Lesenswert?

Schön, dass ich helfen konnte.
Meine Bastelei (kapazitieves volume wheel mit 5 Keys vektoriell 
integriert) arbeitet damit wunderbar.
Lass hören wie dein Eclipse-Projekt fortschreitet :)

Nicki

von Kurt B. (kurt)


Lesenswert?

Hallo Nicholas,
könntest du das vieleicht genauer erklären?

Nicholas Feix schrieb:
> 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]

Anders gefragt, was muss in HID-Keys noch geändert werden?

Mfg,
Kurt

von Nicholas F. (snip3rnick)


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

von Kurt B. (kurt)


Lesenswert?

Danke, ich werde das mal in Ruhe durcharbeiten.

Mfg,
Kurt

von Micha (Gast)


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

von Nico Hood (Gast)


Lesenswert?

Hier gibt es massiv funktionierende USB Descriptors und die 
dazugehörigen reporte:
https://github.com/NicoHood/HID

Guckst du HID.cpp und HID_Reports.h ;)

Mehr konnte ich aus usb HID nicht rausholen. Das einzige was fehlt ist 
rumble für controller, das ist aber komplizierter.

von KazakOFF (Gast)


Lesenswert?

Hey, jemand heraus, mit diesem?

haben einen bereit Quellcode des Projekts?

wenn nicht schwer zu legen, =)

von ;o) (Gast)


Lesenswert?

Please write again without Google Translator.
This automated translations are hard to understand.

von KazakOFF (Gast)


Lesenswert?

Hello, the project is ready? I wanted to see the source code, since I 
did not get (((do on Atmega328

von Andreas S. (drohgebaerde)


Lesenswert?

Nicholas F. posted one example over two years ago - works just fine! - 
and there are several more solutions under Nico Hood's link. :-)

von KazakOFF (Gast)


Lesenswert?

Andreas S, You are using Atmega8?

von Nicholas F. (snip3rnick)


Lesenswert?

@ KazakOFF

It works on almost every AVR MCU with at least 4k of flash memory ;)

: Bearbeitet durch User
von KazakOFF (Gast)


Lesenswert?

Nicholas F, Atmega328 not work (((

von Nicholas F. (snip3rnick)


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 ;)

von KazakOFF (Gast)


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 ?

von KazakOFF (Gast)


Lesenswert?

Nicholas F. , Can upload your file main.c

von Nicholas F. (snip3rnick)


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.

von KazakOFF (Gast)


Lesenswert?

Nicholas F, Upload sample you please.

von Nicholas F. (snip3rnick)


Angehängte Dateien:

Lesenswert?

Sorry for the delay...

Here is the example, but as I said, it could not be tested!
Though it should be easy to rule out remaining errors with the hardware 
to run it ;)

I hope it works for you

von KazakOFF (Gast)


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’

von Nicholas F. (snip3rnick)


Angehängte Dateien:

Lesenswert?

Well, that was a bummer...
Clearly I should have put more time into that, sorry.

I had the chance to set my AVR environment up, so this one actually 
compiled ;)

Though the usbDescriptorHidReport type conflict is on your side, that is 
a false configured 'usbconfig.h'.

: Bearbeitet durch User
von Nicholas F. (snip3rnick)


Lesenswert?

The first file sends the wrong reportID!
I had two reportIDs but removed the first, so it must be 1 instead of 2

sorry again ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.