Bin grade dabei mir Wissen über USB anzueignen. Ich möchte verstehen das
die Geräte am Port von sich geben. Mit der Software "USB-Trace" konnte
ich z.B. feststellen, das die Daten meiner Maus in einen 8Byte Puffer
eingelesen werden, bei Klick: 01 00 00 00 00 00 00 00,
beim loslassen: 00 00 00 00 00 00 00 00.
Soweit, so gut. Aber wie wird dieser Puffer genau gefüllt?! Da der Bus
nur 2 Datenleitungen und keine Taktleitung hat, kann ich es mir nur so
vorstellen:
Der Maus legt die Daten an, und der Host-Controller fragt sie so lange
schnell hintereinander ab, bis der Puffer voll ist. Ist das richtig so?
Wenn ja, wovon hängt der Takt ab mit dem der Controller es einliest? Vom
USB-Typ(1.0, 2.0, 3.0 ...) oder auch vom jeweiligen Gerät? Was mich auch
etwas irritiert: andere Geräte (z.B. Gamepad) haben deutlich größere
Register, und wenn man mehrmals den selben Knopf drückt werden
allerdings nicht immer die selben Daten gesendet.
> Der Maus legt die Daten an, und der Host-Controller fragt sie so lange> schnell hintereinander ab, bis der Puffer voll ist. Ist das richtig so?
Nein, nicht richtig:
1. Es gibt EINEN (und nur einen) Master am USB. Er FRAGT nach, ob ein
Gerät Daten für ihn hat. Das heisst, die Maus legt die Daten nicht von
sich aus auf den Bus, sondern nur, wenn sie gefragt wird.
> Wenn ja, wovon hängt der Takt ab mit dem der Controller es einliest? Vom> USB-Typ(1.0, 2.0, 3.0 ...) oder auch vom jeweiligen Gerät?
Beides. 1.0/1.1 unterstützen 1.5MBit und 12MBit Übertragungsrate, 2.0
zusätzlich 480MBit und 3.0 zusätzlich 5GBit.
Das Gerät teilt dem Bus über einen Pull-Up-Widerstand an EINER (und nur
einer) der beiden Datenleitungen mit, ob es sich um ein Low-Speed
(1.5MBit) oder Full-Speed (12MBit) Gerät handelt.
Ein High-Speed Gerät (480MBit) meldet sich grundsätzlich als
Full-Speed-Gerät an, und schaltet sich danach in den High-Speed-Modus,
wenn es der entsprechende USB-Controller unterstützt.
Wie es bei 3.0 aussieht weiss ich grad nicht, mit 3.0 hab ich mich noch
nicht beschäftigt.
> Was mich auch etwas irritiert: andere Geräte (z.B. Gamepad) haben> deutlich größere Register, ...
Was meinst du mit Register? Kann es sein dass du eigentlich die
Datenpakete meinst? Die maximale Größe der Pakete hängen vom Speed
(Low/Full/High/...) ab. Die tatsächliche Größe hängt davon ab, was das
Gerät tatsächlich braucht. Es macht keinen Sinn, 1024-Byte Pakete zu
senden, wenn davon nur 16 Byte gebraucht werden.
> ...und wenn man mehrmals den selben Knopf drückt> werden allerdings nicht immer die selben Daten gesendet.
Ohne die Daten bzw. das Gamepad zu kennen ist eine genaue Aussage jetzt
schwierig. Ich könnte mir aber vorstellen, dass es evtl. davon abhängig
ist, wie lange die Taste gedrückt ist oder ob nebenbei noch andere
Tasten gedrückt werden.
Generell gibt es dann noch sogenannte USB-Klassen für die Geräte. Ein(e)
Festplatte/USB-Stick gehört zur MassStorageDevice-Klasse, ein(e)
GamePad/Maus zur HumanInterfaceDevice-Klasse, ein Drucker zur
Printer-Klasse, usw.
Die Klasse definiert den Datenaufbau und solche Sachen. Deswegen braucht
man für solche Geräte keinen Treiber installieren, da der PC dann schon
anhand der Klasse einen "generischen" Treiber installieren kann (ist
beim OS mit dabei).
Zur Einführung in USB solltest du diese beiden Seiten mal anschauen:
http://www.usbmadesimple.co.uk/http://www.lvr.com/usb.htm
Ralf
Wurstesser schrieb:> Da der Bus> nur 2 Datenleitungen und keine Taktleitung hat
Die Übertragung ist differentiell, die Leitungen D+ und D- damit
zusammen nur eine einzige Datenleitung. Ein serieller Bus im
Halbduplex-Betrieb eben.
Der Takt ist im Datensignal enthalten und wird vom jeweiligen Empfänger
zurückgewonnen.
Ich erkläre grundlegendes USb nur mal grob und gehe genauer auf die HID
Klasse (Maus, tastatur, etc.) ein:
USB ist ein BUS der nur einen Master, Host genannt, besitzt. Alle
anderen Geräte die am Host angeschlossen sind nennen sich Slaves, von
denen es maximal 127 Stück geben darf. Die Slaves werden vom Host
gefragt ob sie Daten senden möchten oder nicht. Seien dies nun eigene
Daten, antworten auf Anfragen des Host etc., es wird alles vom Host
Initiiert.
USB verfügt über folgende 3 Geschwindigkeitsspezifikationen:
- Low Speed: bis 1,5MBit/sec (USB 1.0/1.1/2.0/3.0)
- Full Speed: bis 12MBit/sec (USB 1.0/1.1/2.0/3.0)
- High Speed: bis 480MBit/sec(USB 2.0/3.0)
- Super Speed: bis 5Gbit/sec (USB 3.0)
Soviel mal Grundlegendes. bei genaueren fragen zu Endpoints, den
unterschiedlichen Transferarten, etc. kannst du gerne genauer
nachfragen.
Nun zur HID Klasse:
USB definiert verschiedene Klassen (Mass Storage, Communications, Audio,
HID, etc.). Mäuse fallen unter die Klasse HID (Human Interface Device).
Zur verfügung stehen bei deiner Maus (die meisten Mäuse laufen nach dem
1.1 Standard) Control und Interrupt transfers zur Verfügung.
Controltransfers werden hauptsächlich für Statusanfragen- antworten und
zur Übertragung gerigner Datenmengen verwendet. Bei Low Speed dürfen nur
8 Byte Packete verwendet werden (respiktive 800Byte/Sekunde). Bei
Full-Speed 8, 16, 32, 64 Byte Packete (respiktive bis zu 64kByte/sec).
Interrupt Transfers bedeuten folgendes: Es wird innerhalb einer vom
Slave definierten zeitlichen Grenze (bsw. 30ms) nachgefragt ob der Slave
neue Daten hat. Es kann also sein das dies mal nur 10ms, 17ms oder auch
die vollen 30ms sind. Aber nie über der definierten Grenze. Die
Datenmengen sidn gleich wie bei den Control Transfers.
Ein USb Slave wird über seine Deskriptoren definiert, derer gibt es
folgende:
- Device Deskriptor
- Configuration Deskriptor
- Interface Deskriptor
- String Deskriptor
- Report Deksriptor (nur bei HID)
Um denn Aufbau deienr gesendeten Datenpackete zu verstehen ist für die
der Report Deskriptor entscheidend. Dieser gibt nämlich an wie die vom
Slave an den Host gesendeten Daten strukturiert sind. Bei einer Maus hat
man bsw. 3 Tasten, sowie eine x und Y Koordinate (für ganz einfache
Mäuse). Bevor überhaupt irgend etwas passiert wird der Host den Slave
nach diesem Deskriptor fragen um zu wissen wo was drinnen steht und wie
die Daten aussehen. Eine Taste kann dabei z.b. nur aus einem Bit
bestehen (für gedrückt/ nicht gedrückt), oder aber auch bsw. aus einem
8Bit Wert um zu identifizieren wie stark sie gedrückt wurde (Beim
Gamepad bsw. um zu zeigen wie stark das Auto im Spiel beschleunigen
soll).
Deine Maus wird wohl ein Low-Speed Gerät sein und daher nur 8Byte
Datenpackete senden.
Dein Gamepad wird höchstwahrscheinlich ein 1.1 oder 2.0 Gerät sein um
größere Datenpackete für die vielen verschieden Joysticks, Knöpfe, etc.
zu versenden.
OK. Danke erst mal für die Hilfe. Wie komme ich denn über PC an die
Daten ran in einem eigenen Programm? Ich bräuchte einen Pointer auf den
Puffer, wo die Daten eingelesen werden. Aber wo nehme ich den her?
USBTrace liefert mir keine Addresse dafür, muss ja aber selbst irgendwie
Zugriff auf die Daten haben, sonst könnte es sie nicht anzeigen. Oder
brauche ich ein Handle auf den Hostcontroller?
Wie oben bereits erwähnt liefert Windows (wie es bei Linux aussieht weiß
ich leider nicht, dürfte aber ähnlich sein) einige API Funktionen zum
Zugriff auf HID Geräte. Um dir den Einstieg zu erleichtern hier mal die
Befehlsabfolge mit kurzer Erläuterung:
1. Inkludiere hid.h und setupapi.h
2. Aufruf von HidD_GetHidGuid() um die Guid (Global unique identifier)
aller angeschlossenen HID Geräte zu erhalten
3. Aufruf von SetupDiGetClassDevs() um weitere Inforamtionen der
einzelnen HID-Devices zu erhalten.
4. Aufruf von SetupDiEnumDeviceInterface()um einen zeiger auf eine
Schnittstelle der Devices zu erhalten.
5. Aufruf von SetupDiGetDeviceInterfaceDetail() um den Gerätepfadnamen
zur Öffnung der Kommunikation zu erhalten.
6. Aufruf von CreateFile() um ein handle für das Gerät zu erhalten.
7. Aufruf von HidD_GetAttributes() um die Hersteller und Produkt-ID des
Gerätes zu erhalten.
8. Stimmen die Hersteller und Produkt-Api mit deiner gesuchten überein
kannst du mit dem Handle weiterarbeiten. Ansonsten musst du es über
CloseFile() wieder schließen und bei Schritt 6 mit dem nächsten Gerät
fortfahren bis du das richtige gefunden hast.
Im Anschluss kannst du mit ReadFile() und WriteFile() Daten zum
HID-Device schreiben oder Lesen.
Es gibt fertige library's die dieses ganze Prozedere wesentlich
vereinfachen. Ich habe eine der man nur die Hersteller- und Produkt-ID
sowie wenn gewünscht den Namen des Gerätes übergibt und die alles
weitere selber macht und das passende handle zurückgibt. Im Anschluss
kann man dan einfach über ReadFile() und WriteFile() arbeiten.
Entweder finde ich sie noch online (war nicht von mir) oder ich suche
sie zu Hause mal.
Ich habe die von mir verwendete HID API nun gefunden:
http://www.signal11.us/oss/hidapi/
Sie ist sehr simpel gehalten und dient für eifnachen Austausch von
Reports zwischen Host und Device. Für mehr Funktionalität sollte man
sich libhid (basiert auf libusb) ansehen. Ist natürlich etwas
komplizierter aber auch wesentlich mächtiger.