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
charusbHidReportDescriptor[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
charusbHidReportDescriptor[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
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.
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?
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
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.
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)
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.
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.
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
PROGMEMcharusbHidReportDescriptor[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:
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
intmain(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
return0;
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
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!
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
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
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
staticucharreportBuffer[2];/* buffer for HID reports */
2
3
...
4
5
staticvoidbuildReport(ucharkey)
6
{
7
/* This (not so elegant) cast saves us 10 bytes of program memory */
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
staticucharreportBuffer[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
PROGMEMcharusbHidReportDescriptor[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
staticvoidbuildReport()// 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
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
constcharusbHidReportDescriptor[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
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.
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 ;)
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.
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
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’
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'.