Hallo,
ich hab bei den Descriptoren etwas nicht verstanden, und zwar;
Woher wissen die Endpoints zu welchen Interfaces sie gehoeren.
Konkret: Ich hab schreib eine Firmware fuer einen uC mit 2 Interaces.
Jedes Interface bekommt 2+1 Endpoints(In und Out, und Endpoint0). Wie
kann ich bei den Endpoint descriptoren angeben, dass sie zum jenen
Interface gehoeren?
Wenn ich das Device als HID anmelde und mehrere Interfaces besitzt, wird
jedes Interface als eigenes Device im Geraetemanager angezeigt?
Gruss
Bernhard
> Woher wissen die Endpoints zu welchen Interfaces sie gehoeren.
Deskriptoren sind abhängig von der Lage. Endpoint-Descriptoren folgen
immer einem Interface-Descriptor, stehen diesem niemals voran. Ein
Endpunkt gehört immer zum direkt vorangegangenen Interface-Descriptor.
Beispiel:
Interface1-HID-Endpoint1-Endpoint2-Interface2-Endpoint3-Endpoint4
Endpoint1 und Endpoint2 ist Interface1 vorangegangen, dazu gehören sie
dann auch. Von EP3 und EP4 nach links gesehen ist Interface2 der nächste
erreichbare Deskriptor, diesem Interface gehören sie dann an.
EP0 gehört immer dem Gerät und lässt sich nicht zuordnen. Alle
Interfaces teilen sich diesen Endpunkt.
> Wenn ich das Device als HID anmelde und mehrere Interfaces besitzt, wird> jedes Interface als eigenes Device im Geraetemanager angezeigt?
Jawoll.
Vielen Dank Rene, fuer die praeziese Antwort.
Wie kann ich auf die verschiedenen Endpoints ueber HID zugreifen?
Ich hab bis jetzt immer nur Reports und Features gefunden. Mir scheint
als laufen die alle ueber den Control Endpoint.
Ich benutze die hid.lib und setupapi.lib von MS DDK.
Gruss Bernhard
P.S. Kennt jemand ein ausfuehrliches Buch ueber USB-HID?
> Wie kann ich auf die verschiedenen Endpoints ueber HID zugreifen?Du kannst das gar nicht, der Treiber entscheidet über das Was und
Wohin, siehe unten.
> Ich hab bis jetzt immer nur Reports und Features gefunden.
Genau so ist es, die Kommunikation mit einem HID läuft einzig und allein
über Reports (Features sind auch in Reports verpackt). Auch werden immer
ganze Reports verschickt. Es ist nicht möglich, nur einen Teil der in
einem Report-Deskriptor beschrieben Daten zu versenden.
> Mir scheint als laufen die alle ueber den Control Endpoint.
Das kann sein, muß aber nicht sein. Wenn ein HID keinen Endpoint
besitzt, muß EP0 genommen werden (Set_Report, Get_Report). Wenn das HID
einen zusätzlichen Interrupt-IN-EP besitzt, wird natürlich dieser für
Input-Reports verwendet. So ist es auch für die andere Richtung. Besitzt
das HID einen Interrupt-OUT-EP, wird auch dieser OUT-EP verwendet (es
sei denn, Du arbeitest mit Win98, erste Version).
Der Treiber weiß anhand der Deskriptoren wohin die Reports gehen / woher
sie kommen und erledigt den Transfer für Dich. Du mußt, wie gesagt, nur
einen gültigen Report zusammenstellen.
> Ich benutze die hid.lib und setupapi.lib von MS DDK.
Wenn Du per SetupDiGetDeviceInterfaceDetail den Pfad zum Gerät ermittelt
und es damit geöffnet hast, sendest Du deine Output-Reports mit
WriteFile und empfängst Input-Reports mit ReadFile.
Obacht: Wenn Du Dir die Capabilities Deines Geräts genauer anschaust
(HidP_GetCaps, HIDP_CAPS), wirst Du feststellen, daß
HID_CAPS.XxxReportByteLength jeweils ein Byte größer ist als der
zugehörige tatsächliche Report. Das wird gemacht, um mit Report-IDs
arbeiten zu können. Das erste Byte, noch vor dem eigentlichen Report,
ist dann eben auch dieser Report-Identifier. Da ich Dir unterstelle,
nicht mit IDs zu arbeiten, mußt Du dieses Byte nullen. Initialisierst Du
dieses Byte nicht oder nicht richtig, werden die Funktionen ReadFile,
WriteFile, HidD_XetFeature fehlschlagen!
> P.S. Kennt jemand ein ausfuehrliches Buch ueber USB-HID?
Jan Axelsons Werke sind zwar Bücher über den USB an sich, sind aber
absolut HID zentriert. Ein reines HID Buch gibt es meines Wissens nicht.
Aber für die Feinheiten gibt es immer noch die offizielle Spezifikation
und, wenn das nicht hilft, dieses Forum hier. ;-)
Hallo,
hab ich nun folgendes Problem:
Ich frage mit SetupDiGetDeviceInterfaceDetail den Pfad meines USB-HID
Geraetes ab, und speichere den Pfad in der Variable "devicePath". In der
Pfadangabe kann ich den VID und PID sehen, und ist soweit richtig.
Wenn ich nun ein CreateFile ausfuehren moechte, bekomme ich ein
INVALID_HANDLE zurueck.
Mein Aufruf sieht so aus:
HANDLE hHidDeviceHandle = CreateFile(devicePath, GENERIC_READ |
GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Geraet wird ordnungsgemaess angemeldet. Ich kann die Descriptoren mit
HClient aus dem DDK von MS abfragen und ueberpruefen.
Laut HClient stimmt alles.
Mach ich hier was falsch?
Wenn CreateFile fehlschlägt, erfährst Du den Grund hierfür von
GetLastError. Diesen Fehlercode hätte ich schon gern gewusst, bevor ich
mir weiter Gedanken mache.
Richtig, das ist ERROR_ACCESS_DENIED (winerror.h). Das kann passieren,
wenn das Gerät bereits belegt ist, da Du das Gerät exclusive öffnen
willst. So wirst Du beispielsweise Schwierigkeiten bekommen, eine Maus
exclusive zu öffnen, solange das System die Maus verwendet.
Du hast jetzt zwei Möglichkeiten zur Abhilfe:
1) Du beendest das Programm, das das HID bereits verwendet.
2) Du teilst Dir das Gerät mit dem anderen Programm (Parameter 3 von
CreateFile). Das Teilen funktioniert natürlich nur, wenn das andere
Programm dies zulässt und das Gerät nicht seinerseits exclusive geöffnet
hat (also mit Parameter 3 von CreateFile = 0).
Ok, Loesung 1 hat geholfen. Thx
Ich benutz den TIUSB 3410 mit Application Loader.
Der Loader hatte die ganze Zeit das Device blockiert.
Bekomm jetzt erfolgreich, ueber EP0 und desweiteren EP1 im Interrupt
Modus, Uebertragungen zustande.
Komisch ist, wenn ich BULK Transfer im Descriptor waehle, dass die
Pakete jetzt ueber EP0 geschickt werden und nicht mehr ueber EP1.
Da EP0 nur einen 8 Byte Puffer hat werden groessere Pakete aufgeteilt,
und meine Datenrate geht in den Keller.
Ein HID kommuniziert ausschließlich über Interrupt Transfers. Neben dem
EP0 hast Du maximal einen Interrupt-IN EP und maximal einen
Interrupt-OUT EP. Wenn einer dieser beides EPs fehlt, wird
selbstverständlich auf EP0 zurückgefallen, Dein Bulk-EP ignoriert.
Das Verhalten, das Du siehst, ist also völlig in Ordnung. Du kannst
sogar froh sein, daß Dir der Treiber das fehlerhafte Gerät nicht gleich
deaktiviert und versucht, aus der verkorksten Situation noch das Beste
zu machen.
Ist es eigentlich möglich, verschieden große Datenpakete zu verschicken
mit nur einem Report?
Ich möchte nicht für jede Paketgröße einen eigenen Report mit
entsprechender Länge anlegen.
> Ist es eigentlich möglich, verschieden große Datenpakete zu verschicken> mit nur einem Report?
Wie ich bereits im zweiten Beitrag schrieb: Nein, das ist nicht möglich.
Ein Report ist ein Report und so wird er auch verschickt.
Mach den Report groß genug, stelle den Nutzdaten die tatsächliche Länge
voran und fülle den unbenutzten Rest mit nullen auf.
> Warum auffüllen, ist doch unnötig.
Die Länge eines Reports, den Du sendest, muß exakt mit der im Deskriptor
ausgiesenen Länge überein stimmen. Du darfst nicht weniger Bytes
übertragen als ausgewiesen. Zumindest unter meinem Windows bekomme ich
Reports nicht gelesen, wenn ich, wie von Dir vorgeschlagen, irgendetwas
in einer nicht bekannten Länge sende. Das füllen des FIFOs ist daher
nicht unnötig, IMO.