Folgende Frage treibt mich um: Ist es möglich ein USB-Gerät zu haben das folgende Eigenschaften hat? * Das Gerät hat Endpoints für 64 Byte in und 64 Byte out * Es wird unter Windows keine Treiberinstallation vom Nutzer verlangt, ein generischer HID-Treiber oder wasauchimmer wird automatisch geladen * Man kann es mit der Windows API oder libhidapi oder libusb oder dergleichen öffnen, Daten senden und empfangen. * Obiges funktioniert mit allen Windows Versionen ab 7 aufwärts Also kein Joystick oder Maus mit nur wenigen buttons und Daten in ner festen Struktur sondern ich brauche die vollen 64 Byte, und zwar in beide Richtungen. Oder muss ich tricksen und einen Joystick mit 512 Buttons definieren? Geht das prinzipiell mit den mitgelieferten Windows-HID-Treibern oder kann ich mir das abschminken? Und falls es das tatsächlich geben sollte wie sähe der Interface-Descriptor aus? Wie sähe der HID-Descriptor aus und welche zusätzlichen Descriptoren (Report?) bräuchte ich noch und wann/wo würde ich die senden oder wann/wo würden die abgefragt?
:
Bearbeitet durch User
Ja, geht alles. Schau Dir mal die AN82078 von Cypress an. Geht zwar darum, einen PSoC mit dem PC zu verheiraten, aber ist sehr gut erklaert. Ich habe dieses Beispiel gerade auf 32 byte aufgebohrt, 64 sind Maximum.
Ich denke das geht. Ich bin mir sogar fast sicher, dass ich so eines habe. Basiert auf dem USBDevice-HID-Custom Beispiel der Microchip_Libraries_for_Applications. Der Descriptor sähe z.B. so aus:
1 | /* Device Descriptor */
|
2 | const USB_DEVICE_DESCRIPTOR device_dsc= |
3 | {
|
4 | 0x12, // Size of this descriptor in bytes |
5 | USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type |
6 | 0x0200, // USB Spec Release Number in BCD format |
7 | 0x00, // Class Code |
8 | 0x00, // Subclass code |
9 | 0x00, // Protocol code |
10 | USB_EP0_BUFF_SIZE, // Max packet size for EP0, see usb_config.h |
11 | 0x04D8, // Vendor ID |
12 | 0x003F, // Product ID: Mouse in a circle fw demo |
13 | 0x0002, // Device release number in BCD format |
14 | 0x01, // Manufacturer string index |
15 | 0x02, // Product string index |
16 | 0x00, // Device serial number string index |
17 | 0x01 // Number of possible configurations |
18 | };
|
19 | |
20 | /* Configuration 1 Descriptor */
|
21 | const uint8_t configDescriptor1[]={ |
22 | /* Configuration Descriptor */
|
23 | 0x09,//sizeof(USB_CFG_DSC), // Size of this descriptor in bytes |
24 | USB_DESCRIPTOR_CONFIGURATION, // CONFIGURATION descriptor type |
25 | 0x29,0x00, // Total length of data for this cfg |
26 | 1, // Number of interfaces in this cfg |
27 | 1, // Index value of this configuration |
28 | 0, // Configuration string index |
29 | _DEFAULT | _SELF, // Attributes, see usb_device.h |
30 | 50, // Max power consumption (2X mA) |
31 | |
32 | /* Interface Descriptor */
|
33 | 0x09,//sizeof(USB_INTF_DSC), // Size of this descriptor in bytes |
34 | USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type |
35 | 0, // Interface Number |
36 | 0, // Alternate Setting Number |
37 | 2, // Number of endpoints in this intf |
38 | HID_INTF, // Class code |
39 | 0, // Subclass code |
40 | 0, // Protocol code |
41 | 0, // Interface string index |
42 | |
43 | /* HID Class-Specific Descriptor */
|
44 | 0x09,//sizeof(USB_HID_DSC)+3, // Size of this descriptor in bytes |
45 | DSC_HID, // HID descriptor type |
46 | 0x11,0x01, // HID Spec Release Nr. in BCD format (1.11) |
47 | 0x00, // Country Code (0x00 for Not supported) |
48 | HID_NUM_OF_DSC, // Number of class descriptors, see usbcfg.h |
49 | DSC_RPT, // Report descriptor type |
50 | HID_RPT01_SIZE,0x00, //sizeof(hid_rpt01) report descriptor |
51 | |
52 | /* Endpoint Descriptor */
|
53 | 0x07,/*sizeof(USB_EP_DSC)*/ |
54 | USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor |
55 | HID_EP | _EP_IN, //EndpointAddress |
56 | _INTERRUPT, //Attributes |
57 | 0x40,0x00, //size |
58 | 0x01, //Interval |
59 | |
60 | /* Endpoint Descriptor */
|
61 | 0x07,/*sizeof(USB_EP_DSC)*/ |
62 | USB_DESCRIPTOR_ENDPOINT, //Endpoint Descriptor |
63 | HID_EP | _EP_OUT, //EndpointAddress |
64 | _INTERRUPT, //Attributes |
65 | 0x40,0x00, //size |
66 | 0x01 //Interval |
67 | };
|
68 | |
69 | //Language code string descriptor
|
70 | const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[1];}sd000={ |
71 | sizeof(sd000),USB_DESCRIPTOR_STRING,{0x0409 |
72 | }};
|
73 | |
74 | //Manufacturer string descriptor
|
75 | const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[27];}sd001={ |
76 | sizeof(sd001),USB_DESCRIPTOR_STRING, |
77 | {'A',' ','M','i','c','r','o','c','h','i','p',' ', |
78 | 'T','e','c','h','n','o','l','o','g','y',' ','I','n','c','.' |
79 | }};
|
80 | |
81 | //Product string descriptor
|
82 | const struct{uint8_t bLength;uint8_t bDscType;uint16_t string[35];}sd002={ |
83 | sizeof(sd002),USB_DESCRIPTOR_STRING, |
84 | {'S','i','m','p','l','e',' ','H','I','D', |
85 | ' ','D','e','v','i','c','e',' ','D','e', |
86 | 'm','o',' ','(','-','>', |
87 | #if defined(__18F14K50)
|
88 | '1','8','F','1','4','K','5','0',')' |
89 | #elif defined (__18F4550)
|
90 | ' ','1','8','F','4','5','5','0',')' |
91 | #elif defined(__18F27J53)
|
92 | '1','8','F','2','7','J','5','3',')' |
93 | #elif defined(__18F25K50)
|
94 | '1','8','F','2','5','K','5','0',')' |
95 | #elif defined(__16F1459)
|
96 | ' ','1','6','F','1','4','5','9',')' |
97 | #elif defined(__16F1455)
|
98 | ' ','1','6','F','1','4','5','5',')' |
99 | #else
|
100 | #warning "Which PIC ???"
|
101 | #endif
|
102 | }};
|
103 | |
104 | //Class specific descriptor - HID
|
105 | const struct{uint8_t report[HID_RPT01_SIZE];}hid_rpt01={ |
106 | {
|
107 | 0x06, 0x00, 0xFF, // Usage Page = 0xFF00 (Vendor Defined Page 1) |
108 | 0x09, 0x01, // Usage (Vendor Usage 1) |
109 | 0xA1, 0x01, // Collection (Application) |
110 | 0x19, 0x01, // Usage Minimum |
111 | 0x29, 0x40, // Usage Maximum //64 input usages total (0x01 to 0x40) |
112 | 0x15, 0x01, // Logical Minimum (data bytes in the report may have minimum value = 0x00) |
113 | // 0x25, 0x40, // Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255)
|
114 | 0x26, 0xFF, 0x00, // Logical Maximum (data bytes in the report may have maximum value = 0x00FF = unsigned 255) |
115 | 0x75, 0x08, // Report Size: 8-bit field size |
116 | 0x95, 0x40, // Report Count: Make sixty-four 8-bit fields (the next time the parser hits an "Input", "Output", or "Feature" item) |
117 | 0x81, 0x00, // Input (Data, Array, Abs): Instantiates input packet fields based on the above report size, count, logical min/max, and usage. |
118 | 0x19, 0x01, // Usage Minimum |
119 | 0x29, 0x40, // Usage Maximum //64 output usages total (0x01 to 0x40) |
120 | 0x91, 0x00, // Output (Data, Array, Abs): Instantiates output packet fields. Uses same report size and count as "Input" fields, since nothing new/different was specified to the parser since the "Input" item. |
121 | 0xC0} // End Collection |
122 | };
|
123 | |
124 | |
125 | //Array of configuration descriptors
|
126 | const uint8_t *const USB_CD_Ptr[]= |
127 | {
|
128 | (const uint8_t *const)&configDescriptor1 |
129 | };
|
130 | |
131 | //Array of string descriptors
|
132 | const uint8_t *const USB_SD_Ptr[]= |
133 | {
|
134 | (const uint8_t *const)&sd000, |
135 | (const uint8_t *const)&sd001, |
136 | (const uint8_t *const)&sd002 |
137 | };
|
Der Transfer geht dann über die beiden definierten Endpoints...
:
Bearbeitet durch User
Ja, das scheint tatsächlich zu funktionieren, immerhin habe ich es jetzt mit Inspiration der oben geposteten Descriptoren und darauf aufbauend weiterer Google-Recherche geschafft eine erfolgreiche Enumerierung sowohl unter Windows als auch unter Linux hinzubekommen und letzte Nacht hat zum ersten Mal der zweite Endpoint in beide Richtungen erste Lebenszeichen (unter Linux) von sich gegeben. Ich ringe nun nur noch ein bisschen mit der praktischen Implementation auf meiner Hardware, insbesondere dem Verständnis der Kinetis USB-Hardware und ihren Zuständen und auch den Feinheiten des USB-Protokolls. Sehr große Hilfe beziehe ich dabei übrigens auch aus der bemerkenswerten Arbeit von Kevin Cuzner: http://kevincuzner.com/2014/12/12/teensy-3-1-bare-metal-writing-a-usb-driver/ der nicht müde geworden ist sich durch die nur schwach dokumentierte Kinetis USB-Hardware zu kämpfen und seine gewonnenen Erkenntnisse zu teilen. Wenn ich es fertig habe werde ich es ebenfalls auf Github einstellen.
Scheint ich hab mich zu früh gefreut. Wie es aussieht ist unter Windows 7 der generische HID-Treiber broken und sendet Datenmüll: Wenn ich an die WriteFile() Funktion keinen Buffer übergebe mit exakt der Länge 65 Bytes (also Reportgröße plus 1) kommt 1784 RROR_INVALID_USER_BUFFER und wenn ich nicht in das erste Byte die Report-ID eintrage dann kommt 87 ERROR_INVALID_PARAMETER. gesendet werden dann jedoch die ersten 64 Byte des Buffers incl. der Report-ID und das letzte Byte wird abgeschnitten. Mit dem nächsten Paket kommts auch nicht, es fällt einfach unter den Tisch. Unter Linux funktionierts natürlich korrekt. Also wieder extra Gefrickel nur für bestimmten Windows-Versionen. Wär ja auch zu schön gewesen wenn stattdessen mal was einfach normal funktionieren könnte :-(
Bernd K. schrieb: > Scheint ich hab mich zu früh gefreut. Wie es aussieht ist unter Windows > 7 der generische HID-Treiber broken und sendet Datenmüll: Also bei mir funktioniert es mit Win7 und Linux gleich. (Gleiche Qt Source -> http://www.hs-ulm.de/wir/Personal/PersonalSaSchr/vschilli/QtProjekte/) Verwendet wurde die HIDAPI von Alan Ott (http://www.signal11.us/oss/hidapi/).
:
Bearbeitet durch User
Bernd K. schrieb: > Wie es aussieht ist unter Windows 7 der generische HID-Treiber broken > und sendet Datenmüll Wenn dein Gerät nicht HID-, sondern WinUSB-Deskriptoren hat, dann gibt es keinen Protokoll-Treiber, der dir dazwischenfunken könnte, und du kannst in allen Betriebssystem ohne Kernel-Treiber darauf zugreifen. (Und kannst Bulk-Transfers.)
Volker S. schrieb: > Verwendet wurde die HIDAPI von Alan Ott > (http://www.signal11.us/oss/hidapi/). Das ist der Code den ich benutzte um eine zweite Meinung einzuholen, das linkt gegen die hidapi. Es verhält sich genauso wie mein erster Versuch direkt über das Windows API mit CreateFile()/WriteFile().
1 | import hid |
2 | |
3 | x = [16]*65 |
4 | y = [17]*65 |
5 | |
6 | x[0] = 2 # report ID |
7 | x[1] = 4 # erstes |
8 | x[63] = 5 # vorletztes |
9 | x[64] = 6 # letztes |
10 | |
11 | y[0] = 2 # report ID |
12 | y[1] = 7 # erstes |
13 | y[63] = 8 # vorletztes |
14 | y[64] = 9 # letztes |
15 | |
16 | d = hid.device() |
17 | d.open(0x1234, 0x5694) |
18 | |
19 | # paar mal senden
|
20 | for i in range(3): |
21 | d.write(x); |
22 | d.write(y); |
23 | |
24 | d.close() |
Bei allen Paketen wird die Report-ID vorangestellt. Bei den ersten beiden Paketen wird das letzte Byte komplett verschluckt, es kommen also nur 63 Byte Nutzdaten an. Bei den folgenden wird dann jedesmal das fehlende Byte in einer weiteren OUT Transaktion der Länge 1 nachgereicht. Ob dabei immer noch was verschluckt wird hab ich nicht getestet. Es sieht wohl so aus als sollte ich die Report-Größe auf 63 Byte verringern um zu verhindern daß er bei jedem Paket immer noch ein einzelnes Byte in einem zweiten fast leeren Paket hinterher schicken muss.
Clemens L. schrieb: > Wenn dein Gerät nicht HID-, sondern WinUSB-Deskriptoren hat, dann gibt > es keinen Protokoll-Treiber, der dir dazwischenfunken könnte, und du > kannst in allen Betriebssystem ohne Kernel-Treiber darauf zugreifen. Was sind "WinUSB-Deskriptoren"? Meinst Du ne spezielle Interfaceklasse oder meinst Du wirklich irgendwelche MS-proprietären Nicht-Standard-Deskriptoren (und welche Klasse ist es dann, und welcher Treiber wird dann unter Linux geladen)? Und was passiert unter Windows wenn man es einstöpselt? Gelbes Ausrufezeichen? Ich will unter allen Umständen vermeiden daß der Benutzer irgendwelche Aktionen durchführen muss nach erstmaligem Einstöpseln auf jungfräulichem Windows.
:
Bearbeitet durch User
Bernd K. schrieb: > Wenn ich es fertig habe werde ich es ebenfalls auf Github einstellen. Ich lasse den Worten mal Taten folgen: https://github.com/prof7bit/frdm-kl25z-minimal-usb-hid Das läuft (stand heute Abend) unter Linux. Unter Windows hab ichs noch nicht getestet. Das Projekt (so wie es ist) erfordert Hardware: * FRDM-KL25Z Board (mit Segger-Firmware gemodded) Software: * J-Link Software * arm-none-eabi-gcc * python-3.x * bash * make Python ist erforderlich um die usb_descriptors.c/.h zu generieren. Das Projekt kompiliert nach dem Auschecken direkt auf der Konsole mit make oder alternatiuv dazu hab ich auch noch Projektdateien für Eclipse (mit GNU-ARM und PyDev Plugins) beigelegt. Ein kleines Python script zum Test hab ich auch noch beigelegt, momentan noch 2.x weil ich auf die Schnelle das verwendete hid Modul noch nicht für python 3.x gefunden hab auf meiner Ubuntu-Kiste, scheint aber noch andere hidapi bindings zu geben, war nur zu faul zum Suchen.
Zählt die Report-ID nicht zum Report dazu (zählt also eigentlich zu den 64 Bytes und kommt nicht noch oben drauf)? Ich hätte vermutet, dass man die Angabe einer Report-ID im Descriptor weg lassen müsste um volle 64 Bytes nutzen zu können, oder nur 63 Bytes an Nutzdaten bei Angabe einer Report-ID und Report-Count=64 im Descriptor hätte?
Bernd K. schrieb: > Was sind "WinUSB-Deskriptoren"? Meinst Du ne spezielle Interfaceklasse > oder meinst Du wirklich irgendwelche MS-proprietären > Nicht-Standard-Deskriptoren Letzteres: https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799.aspx > A WinUSB device is a Universal Serial Bus (USB) device whose firmware > defines certain Microsoft operating system (OS) feature descriptors > that report the compatible ID as "WINUSB". > > The purpose of a WinUSB device is to enable Windows to load Winusb.sys > as the device's function driver without a custom INF file. > und welche Klasse ist es dann Alles andere als "vendor specific" wäre sinnlos. > und welcher Treiber wird dann unter Linux geladen)? Linux ignoriert diese Deskriptoren. Aber in Linux benötigt libusb auch keinen speziellen Kerneltreiber. > Und was passiert unter Windows wenn man es einstöpselt? Nichts besonderes. Dein Programm muss sich dann das Gerät über die WinUSB-API selbst heraussuchen.
:
Bearbeitet durch User
Clemens L. schrieb: >> Und was passiert unter Windows wenn man es einstöpselt? > > Nichts besonderes. Geht das auch mit Windows 7? Oberflächliches Googeln legt nahe daß ich dort noch ein .inf brauche. Dann scheidet das leider aus.
Bernd K. schrieb: > Geht das auch mit Windows 7? "For versions of Windows earlier than Windows 8, the updated Winusb.inf is available through Windows Update. If your computer is configured to get driver update automatically, WinUSB driver will get installed without any user intervention by using the new INF package."
gnarf schrieb: > Zählt die Report-ID nicht zum Report dazu (zählt also eigentlich zu den > 64 Bytes und kommt nicht noch oben drauf)? > Ich hätte vermutet, dass man die Angabe einer Report-ID im Descriptor > weg lassen müsste um volle 64 Bytes nutzen zu können, oder nur 63 Bytes > an Nutzdaten bei Angabe einer Report-ID und Report-Count=64 im > Descriptor hätte? Genau so ist es auch. Aber bei insgesamt 64 Bytes ist Schluss. Also ohne ID (64 Bytes Nutzdaten) oder mit ID (63 Bytes an Nutzdaten). Sonst packt das der Firmware-Treiber nicht. Die machen nämlich meist bei 64 Bytes (gesamt) zu. Schau mal hier: http://ahidlib.com/pages/fundamentals.php?lang=de
Peter schrieb: > Also ohne ID (64 Bytes Nutzdaten) oder mit ID (63 Bytes an Nutzdaten). Danke für den Hinweis, das funktioniert :-) Durch das simple Weglassen der beiden report-id Einträge im Report-Descriptor wird keine Report-ID mehr vorangestellt und ich kann die Reportgröße auf 64 Bytes erweitern. Allerdings muss man beachten dass der Windows-Treiber jetzt in der WriteFile() Funktion einen Puffer von exakt 65 Bytes erwartet bei dem das erste Byte zwingend 0 sein muss, gesendet werden jedoch nur die hinteren 64 Bytes des Puffers. Umgekehrt muss auch der Buffer der für die ReadFile() Funktion vorgehalten wird exakt 65 Bytes betragen, die Nutzdaten landen in den hinteren 64 Byte und das erste Byte kann man ignorieren. Bei Verwendung von HIDAPI (unter Python) ist es sendeseitig genauso wie beim nackten Windows WriteFile(), also 65 Byte, aber empgfangsseitig scheinen auch 64 Byte zu reichen, zumindest bei den cython-hidapi Bindings ist das so. Zum Glück anscheinend unter Linux und Windows gleichermaßen.
Bernd K. schrieb: > Allerdings muss man beachten dass der Windows-Treiber jetzt in der > WriteFile() Funktion einen Puffer von exakt 65 Bytes erwartet bei dem > das erste Byte zwingend 0 sein muss, gesendet werden jedoch nur die > hinteren 64 Bytes des Puffers. > > Umgekehrt muss auch der Buffer der für die ReadFile() Funktion > vorgehalten wird exakt 65 Bytes betragen, die Nutzdaten landen in den > hinteren 64 Byte und das erste Byte kann man ignorieren. Genau so ist das. Man könnte auch sagen: Egal ob das HID-Gerät eine ID definiert oder nicht, der Windows Treiber (WriteFile(), ReadFile()) sendet / empfängt im ersten Byte immer eine ID (entweder die definierte oder eben 0). Die Puffer-Größe auf Windows-Seite entspricht dabei immer der Größe im Report-Deskriptor + 1 (für die ID).
Hab mal schnell ein HIDAPI Binding für Free Pascal auf Linux gemacht: https://github.com/prof7bit/HIDAPI.pas
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.