Forum: Projekte & Code USB HID Host Treiber für Windows


von Potter S. (potter68)


Lesenswert?

Hallo,

ich möchte hiermit einmal meinen USB HID Host Treiber für Windows 
vorstellen!

Auf Mikrocontroller Seite gibt es mittlerweile von jedem Hersteller 
USB-Stacks, um ein Device zu implementieren. Und auch auf PC-Seite sind 
einige Host Treiber verfügbar. Warum also noch ein Treiber? Ganz einfach 
weil deren Anwendung oft zu kompliziert ist!

Mein Treiber kommt als Bibliothek (.lib) daher und läßt sich einfach 
über eine Header-Datei in die Projekte einbinden. Das Ganze funktioniert 
mit dem Microsoft Visual Studio Express (C++) zusammen.

Folgende Funktionen sind implementiert:

- AHid_Init(): muß am Anfang aufgerufen werden und initiaisiert die Bib.
- AHid_Register(): registriert ein USB-Gerät zur Verwendung.
- AHid_Read()/AHid_Write(): wie die Namen schon sagen.
- AHid_Attached(): stellt den Anschluß an den USB fest.

Vom technischen her ist die Bibliothek so aufgebaut, dass zum Lesen und 
Schreiben jeweils eigene Threads implementiert sind, was dazu führt, daß 
die Anwendung nicht 'hängen bleibt'. Der Lesethread sendet nach 
erfolgreichem Datenempfang eine Nachricht an das Hauptfenster. Dort 
werden dann die Daten mit AHid_Read() in Empfang genommen und 
weiterverarbeitet.

Bei Anschluß oder Entfernen des USB-Geräts erhält die Anwendung eine 
WM_DEVICECHANGE-Nachricht. Hierauf wird mit AHid_Attached() überprüft, 
in wie weit das eigene USB Gerät betroffen ist.

Das Ganze ist in eine Demo integriert, die ich mit der WIN32 API 
geschrieben habe (kleine Dialog-Anwendung). Wer interesse hat kann sich 
die ahid.lib hier herunterladen: www.embedded24.net.

Für Fragen und Verbesserungen bitte bei mir melden (entweder hier oder 
unter e24(at)basic.io).

Gruß Potter

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Ich war mal auf deiner Website, aber was genau ist der Unterschied 
zwischen:

- free: no commercial use (download)
- private: no commercial use
- commercial: commercial use

Also den Unterschied zwischen den ersten beiden versteh ich nicht...

von Potter S. (potter68)


Lesenswert?

Hallo Julian,

der wesentliche Unterschied ist, dass in der kostenlosen Version 
lediglich eine Schnittstelle (ein HID-Gerät und eine Report ID) 
unterstützt wird.

Gruß Potter

von ... (Gast)


Lesenswert?

Doku bedarf überarbeitung vid und pid getrent oder als string ? du 
solltest dich schon entscheiden.

Wie kann ich geräde eindeutig identivizieren. VID und PID reichen unter 
umständen nicht aus ( 2 mal das gleiche device am bus und ich wüdre 
gerne mit einem ganz bstimmten reden )

und ich hab das leichte gefühl du hast HID nicht ganz verstanden. hier 
gibt es keine Paket struktur oder sowas. Ein HidReport kann verloren 
gehen oder doppelt "empfangen" werden. Windows frägt in einer von ihm 
gewählten frequenz den HID reports an. Diesen speichert er zwischen. bei 
einem Read auf das device wird "ich vermute" der vorher gelesene wert 
zurückgegeben.


wozu 2 threads. die daten wandern sowieso alle auf den gleichen 
endpoint. spätenstens hier laufen die daten wieder sequenziell über die 
leitung.

Dien hängenbleiben hat eher was mit GUI eigenschaften an sich zu tun.
Man darf nicht inerhalb der on klick methode irgend welche zeitraubenden 
sachen machen. (z.B. auf die rückangwort von einem device oder ... )

von Matthias (Gast)


Angehängte Dateien:

Lesenswert?

Ich wollte es mal ausprobieren, bekomme es aber mit der aktuellen Visual 
C++ 2010 Express nicht zum laufen. Fehler siehe Bild.

von Potter S. (potter68)


Lesenswert?

Hallo Laute,

erstmal vielen Dank, dass Ihr Euch für die ahid.lib interessiert und die 
Demo ausprobiert habt.

@Matthias: tatsächlich erhält man zwei Linker-Warnungen. Allerdings 
führen diese nicht dazu, dass die Anwendung nicht läuft (jedenfalls bei 
mir mit VS 2008). Die Schlußmeldung zeigt ebenfalls an, daß das 
Erstellen erfolgreich war (Schau mal, ob die Applikation nicht doch in 
der Task-Leiste zu finden ist?). Wie auch immer, ich werde mich darum 
kümmern, daß auch diese Warnungen verschwinden.

@...:

Was die Doku betrifft so bedarf diese nicht nur der Überarbeitung - ich 
muß die noch komplett schreiben! Der Grund: ich dachte die Funktionen 
sind so 'übersichtlich', daß ich zunächst auf eine ausführliche Doku 
verzichten kann.

Was die Sache mit VID/PID betrifft hast Du recht. Man sollte sich 
entscheiden. Allerdings war es lediglich so, dass ich zunächst die ID's 
als Interger übergeben habe und mich dann nach (reiflicher) Überlegung 
umentschieden habe und nun diese als String übergebe. Dadurch wird das 
Ganze etwas flexibler! Man hat nun die Möglichkeit auch einzelne 
Interfaces (z.B. bei Composite Devices [Verbundgeräte]) anzusprechen. 
Technisch funktioniert das so, dass der String einfach mit dem 
Gerätepfadnamen verglichen wird. Es mag sein, dass ich im Header File 
noch von VID/PID spreche. Danke für den Hinweis, ich werde es 
verbessern.

Also wenn Du zwei mal das gleiche Device am Bus hast, dann wird das 
ebenfalls über den Gerätepfadnamen erledigt. Dieser wird gebildet aus 
VID, PID und gegf. Interface des USB-Gerätes sowie Gerätetyp (hier HID) 
und dem Port, an dem Dein Gerät angeschlossen ist. Wie Du siehst werden 
diese identischen Geräte über den Port unterschieden. Ich sehe jetzt 
auch keine Notwendigkeit für die Applikation zu wissen ob ich Gerät A 
oder B ansteuere, da ja beide sowieso das gleiche machen. Falls es doch 
Bedarf für so etwas gäbe, dann sag mir ein Beispiel und ich werde noch 
eine Möglichkeit einfügen, um die Geräte-ID abzufragen.

Naja das mit den Paketen ist so eine Redensart. Bei HID's werden Reports 
versendet. Das kann über den Control-Endpunkt oder über einen 
Interrupt-Endpunkt geschehen. Momentan werden Interrupt-Endpunkte 
unterstützt. Den Control-Endpunkt (Feature-Reports) werde ich noch 
implementieren.

Was Du da schreibst bzgl. des Senden und Empfangen von Reports stimmt. 
Allerdings legt zunächst das USB-Geräte (und nicht Windows) fest, in 
welchen Abständen die In-Endpunkte gepollt werden sollen - das meinst Du 
mit Frequenz, oder? Sind dann neue Daten vorhanden, holt diese der Host 
ab und schreibt sie zunächst mal in einen (internen) Datenpuffer. Hier 
wird dann (bei Interrupt-Transfer) mit ReadFile ausgelesen. Beim 
Schreiben an das Gerät funktioniert das genauso nur umgekehrt.

Das mit den Threads führt dazu, dass beim Empfang von vielen Daten (oder 
beim Senden) die Anwendung nicht hängt. Auch das hat nichts mit den 
Endpunkten direkt zu tun. Übrigens: Senden und Empfangen geht sehr wohl 
über zwei verschiedene Endpunkte (nämlich In und Out)! Die ganze USB 
Geschichte ist wirklich nicht trivial. Ich empfehle Dir das Buch von Jan 
Axselson, falls Du noch ein paar Lücken schließen möchtest.

Noch mal Danke für die Resonanz und auch Kritik. Es hilft mir sehr 
dabei, den Treiber zu verbessern.

Gruß Potter

von Matthias (Gast)


Lesenswert?

Ralf H. schrieb:
> @Matthias: tatsächlich erhält man zwei Linker-Warnungen. Allerdings
> führen diese nicht dazu, dass die Anwendung nicht läuft (jedenfalls bei
> mir mit VS 2008). Die Schlußmeldung zeigt ebenfalls an, daß das
> Erstellen erfolgreich war (Schau mal, ob die Applikation nicht doch in
> der Task-Leiste zu finden ist?). Wie auch immer, ich werde mich darum
> kümmern, daß auch diese Warnungen verschwinden.

Die .Exe ist da, hatte ich vergessen zu erwähen. Starten lässt sie sich 
jedoch nicht, meldet sofort einen Aufruffehler. Habe Version 10. Die Lib 
sieht wie für Version 9 aus. Kann es sein, das die nicht zusammen 
passen?

von Potter S. (potter68)


Lesenswert?

Es ist tatsächlich so, dass die Konvertierung (von 2008 auf 2010) nicht 
einwandfrei durchgeführt wird. Der Treiber läuft also momentan nur unter 
der 2008er Version des Visual Studio C++ - ich bin aber dabei das zu 
ändern.

von ... (Gast)


Lesenswert?

Ok das mit den endpoints ist mir entgangen. wobei es ist die gleiche 
leitung und die hat nur D+ und D-. bzw wie du gesagt hast je nach 
realisierung ob controll oder interrupt endpoints.

Ich frage mich gerade wo du von Interrupt und dem Controll endpoint 
redest, ob du hier von windows oder von der FW redest. Auf pc seite kann 
dir das eigentlich recht egal sein. HID api von windows sei dank.

Wiso die devices unterscheidbar sein sollen? wenn die geräte gleich sind 
können sie doch unterschiedliche aufgaben haben. z.B. Weiche1 und 
weiche2 bei ner eisenban oder temp umgebung / temp heizung. wenn ich 
dann ggf jedes mal raten muss welche welche ist und das ggf auch nach 
einem neustart wieder passend drehen und anpassen muss, macht das keinen 
spass.  Serien nummer sollte das device versenden (string descriptor)

windows kann bei usb da lustige sachen manchen z.B. Bei SmartCard hier 
werden die Gerätenamen nach der reihenfolge des erkennens vergeben und 
durchnummeriert. (pscs api) bei einem neustart von system sind die 2 
geräte ja schon angeschlossen. die durchnummerierung erfolgt erneut. nur 
unter umständen in anderer reihenfolge.

Generell werden usb geräte ohne Serien no anahnd ihres steckplates an 
usb erkannt. hast du nun 2 geräte ohne serien no am pc angeschlossen, 
und vertasucht die beiden anschlüsse wird windows keinen unterschied 
ferstellen, und z.B. weiche2 als weiche1 verwenden und umgekehrt.


Ich hab bisher zur geräte erkennung die SetupApi verwendet bzw die HID 
API hier kann man alle am system angeschlossenen geräte abfragen und VID 
PID und ggf SN abfragen und vergleichen und danach mit write / read file 
daten senden und lesen.

beispiel von st:  http://www.st.com/stonline/books/pdf/docs/12179.pdf
oder hier: http://www.c-plusplus.de/forum/62399

ok die notwendigen dateien und libs sollte man haben. SDK bzw. DDK bzw 
WDK keine ahnung wo das jetzt genau drinn ist. und es sieht nach viel 
wodo aus was da gemacht wird. der code funktiniert aber bei mir ganz 
gut.

gruss

von Potter S. (potter68)


Lesenswert?

@Matthias:
Ich habe mir jetzt mal die Express Version vom Visual Studio C++ 2010 
heruntergeladen und das Projekt angepasst. Es sollte nun ohne Fehler 
laufen. Wäre nett, wenn Du das bestätigen könntest.

@...:
Also das Problem mit mehreren identischen USB-Geräte an einem PC wird 
bei der ahid.lib vermieden:

Wenn Du die Demo startest, siehst Du im Ausgabefenster ein paar 
DEBUG-Hinweise. So wird zum Beispiel auch der Gerätepfadname ausgegeben. 
Dieser Name ist - nachdem ein USB-Gerät einmal am USB-Port des PC 
angemeldet wurde - für diesen speziellen Port immer gleich. Er ändert 
sich auch nicht nach einem Neustart des PC!

Wenn Du nun hergehst, und im Betrieb Dein Gerät an einen anderen Port 
ansteckst (also ohne die Applikation zu beenden) wirst Du feststellen, 
dass das USB-Gerät nicht erkannt wird. Der Treiber hat nämlich Dein 
Gerät mit dem ersten Gerätepfadnamen in die Registrierung eingetragen 
und somit erkennt er den falschen Pfad. Erst nach einem Neustart der 
Applikation kannst Du Dein Gerät an einem anderen Port wieder 
registrieren lassen.

Was heisst das nun für mehrere gleichartige Geräte? Da - wie bereits 
erwähnt - die Gerätepfade ausschlaggebend sind für eine Registrierung 
und da diese Gerätepfade alphabetisch durchsucht werden, kannst Du immer 
sicher sein, dass die Reihenfolge und somit die Gerätezuordnung erhalten 
bleibt. Das gilt auch nach einem Neustart des PC.

Anmerken will ich noch, das die Demo-Version auf einen einzelnen 
Gerätepfadnamen eingeschränkt ist. Das reicht für die allermeisten 
privaten Anwendungen.

von Potter S. (potter68)


Lesenswert?

Zwischenbilanz:

- Dynamic Link Library (DLL) hinzugefügt.
- ein paar Fehler entfernt.
- Funktionalität für UNICODE und MULTIBYTE getestet.
- Demos zum Download für C++ und C# (Visual Studio 2010) erstellt.
- Homepage aktualisiert: http://www.embedded24.net
- Artikel zum Thema erstellt: 
http://www.mikrocontroller.net/wikisoftware/index.php?title=USB_HID_Host_Treiber&redirect=no

von Sam (Gast)


Lesenswert?

Update:

- MULTIBYTE Support entfernt (veraltete Technologie)
- Demo-App für Visual Studio VB 2010 erstellt.

von Matthias (Gast)


Lesenswert?

Erstellen unter Version 10 klappt jetzt ohne Compilerfehler.

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.