USB-Port ansprechen
-
Hallo!
Hey, nicht gleich so grob King. scherz
Ich dachte nur, die Software wäre eine günstige Alternative. dickes Schluchzzz...Ich bin aber auch ein Dussel. Habe Euch das falsch erklärt. Der Code ist keine Statusanforderung, sondern dient dazu, sich im Token Ring als PC und Master mit der Adresse 0 anzumelden und um zu sagen, dass ich das Token haben will. Habe auch noch den Hex-Code um Variablen zu lesen und zu schreiben. Dann sollte das, abgesehen vom Report-Identifier, mit WriteFile klappen.
Jetzt verstehe ich auch, was Du mit Parsen der Reports weiter vorn gemeint hast. Gehe ich dabei vor wie beim Enumerieren und brauche ich dazu das Handle auf's Gerät? Blöde Frage vielleicht, wie mache ich das zusätzliche Byte für den Report-Identifier sichtbar aus den Reports und welches ist es? Die MSDN-Seite dazu habe ich.
Danke für Eure Antwort.@surf.
Ich versuche eine SPS über PC und USB zu steuern. Dabei geht's mir darum Variablen zu lesen und diese zu korrigieren, falls sie sich ändern.
-
baschti schrieb:
Gehe ich dabei vor wie beim Enumerieren und brauche ich dazu das Handle auf's Gerät?
Um die Report-Informationen zusammenzustellen, benötigst Du das Geräte-Handle. Schliesslich sind die Reports im Gerät gespeichert und müssen erst von dort gelesen werden. Die Funktion HidD_GetPreparsedData erledigt diesen Teil für Dich. Sind die Report-Descriptoren zusammengesammelt, kannst Du damit arbeiten. Dazu gibt es die ganzen HidP_XXX-Funktionen. Um Dir einen Überblick zu verschaffen, verwendest Du HidP_GetCaps.
In der gefüllten HID_CAPS-Struktur kannst Du nun die benötigten Buffer-Größen für die einzelnen Reports ersehen, inklusive des (ersten) zusätzlichen Bytes (<- für WriteFile einfach auf 0 setzen, IIRC).
Den Einblick vertiefen kannst Du mit HidP_GetButtonCaps und HidP_GetValueCaps.
BTW: Natürlich kannst Du die für die Reports reservierten Buffer direkt bearbeiten. Ich für meinen Teil fand aber die Möglichkeit ganz nett, das Modifizieren von den Funktionen aus hid.dll erledigen zu lassen (HidP_SetUsageValue, HidP_SetUsageValueArray, usw.).
-
Prima, danke. Werde ich gleich mal dran weiterarbeiten.
-
Hallo King!
Ich hoffe, ich nerve nicht zu sehr. Hast Du irgendeinen Fehler in meiner WriteFile/ReadFile-Anweisung weiter vorn gefunden? Denn irgendetwas klappt noch nicht.
Das Parsen der Reports hat folgendes ergeben:
(Hoffe habe alle Informationen, sind arg viele.)Usage: 1 Usage Page: 0xFFA0 Input Report Byte Length: 261 Output Report Byte Length: 261 Feature Report Byte Length: 0 Number of Link Collection Nodes: 1 Number of Input Button Caps: 0 Number of InputValue Caps: 1 Number of InputData Indices: 1 Number of Output Button Caps: 0 Number of Output Value Caps: 1 Number of Output Data Indices: 1 Number of Feature Button Caps: 0 Number of Feature Value Caps: 0 Number of Feature Data Indices: 0 --Input - GetValueCaps:-- Input - ReportID: 0xCC Input - BitField: 0xCCCC Input - BitSize: 0xCCCC Input - LinkCollection: 0xCCCC Input - LinkUsage: 0xCCCC Input - LinkUsagePage: 0xCCCC -Input - GetButtonCaps: Input - ReportID: 0xCC --Output - GetValueCaps:-- Output - ReportID: 0xCC Output - BitField: 0xCCCC Output - BitSize: 0xCCCC Output - LinkCollection: 0xCCCC Output - LinkUsage: 0xCCCC Output - LinkUsagePage: 0xCCCC -Output - GetButtonCaps: Output - ReportID: 0xCC
Der daraus resultierende Code für WriteFile sieht ja dann so aus:
CC 10 00 00 49 49 16
oder? Obwohl mich die Input/Output-ReportByteLength stutzig macht.
um den Input-Report zu parsen: (hier nur für Input, die Capabilities und Output-Anweisungen sind ja ähnlich)
HIDP_CAPS Capabilities; PHIDP_PREPARSED_DATA PreparsedData; HIDP_REPORT_TYPE HidP_Input, HidP_Output; HIDP_BUTTON_CAPS ButtonCaps; PUSHORT ButtonCapsLength; HIDP_VALUE_CAPS ValueCaps; PUSHORT ValueCapsLength; . . . printf("Input - GetValueCaps:\n\n"); HidP_GetValueCaps(HidP_Input, &ValueCaps, ValueCapsLength, PreparsedData); printf("%s0x%X\n", "Input - ReportID: ", ValueCaps.ReportID);
Doch wie sieht die ReadFile-Anweisung aus, um den Report-Identifier mit rein zu bekommen?
Danke für Deine unermüdliche Hilfe!
-
Ich habe mich unglücklich ausgedrückt. Mach Dir nicht so viele Gedanken um das erste Byte, das ist hauptsächlich zur internen Verwendung gedacht. Für Dich ist lediglich wichtig, daß das Byte vorhanden und auf 0 gesetzt ist. Bei ReadFile wird das erste Byte von der Funktion genullt; ich ziehe es jedoch vor, das schon vor dem Aufruf zu erledigen (man weiß ja nie ...).
Dein Aufruf von WriteFile kann so nicht klappen, weil zum Einen das erste Byte nicht 0 und zum Anderen zu kurz ist. Du überträgst lediglich 6 * sizeof(int) Bytes, also 24 an der Zahl (wundert mich sowieso, sollten das nicht Bytes sein?). Du mußt den Report in einem Rutsch übertragen, also alle 261 Bytes zusammen.
Readfile kann so nicht klappen, weil der Buffer mit nur einem einzigen Byte zu knapp bemessen ist. Du mußt alle 261 Bytes in einem Rutsch lesen.
Wenn WriteFile in die Hose geht, gibt es bei HIDs also zwei zusätzliche Fehlerquellen. Ist das erste Byte nicht 0, bekommst Du von GetLastError diesen Fehler:
// // MessageId: ERROR_INVALID_PARAMETER // // MessageText: // // The parameter is incorrect. // #define ERROR_INVALID_PARAMETER 87L // dderror
Ist der an WriteFile übergebene Buffer kleiner oder größer als HID_CAPS.OutputReportByteLength, gibt's diesen Fehler:
// // MessageId: ERROR_INVALID_USER_BUFFER // // MessageText: // // The supplied user buffer is not valid for the requested operation. // #define ERROR_INVALID_USER_BUFFER 1784L
Den zweitgenannten Fehler bekommst Du auch von ReadFile/ GetLastError, wenn der an ReadFile übergebene Buffer in der Größe != HID_CAPS.InputReportByteLength ist.
Deine beiden Aufrufe von HidP_GetValueCaps sind übrigens fehlgeschlagen. Gewöhn Dir ruhig an, auch mal die Rückgabewerte zu checken. Dann hättest Du das gesehen. Ich glaube aber Dir auch so schon sagen zu können, daß eh alles einer einzigen Usage zugeordnet ist. Da kannst Du Dir den folgenden Aufruf von HidP_SetUsageValueArray auch sparen, das wäre irgendwie auch nur ein unnötiges Umherkopieren der Buffer.
Warum genau nun HidP_GetValueCaps bei Dir in die Hose gegangen ist, wird vermutlich an ValueCapsLength liegen, was ja bei Dir ein Pointer ist. Und dieser Pointer zeigt nun irgendwo ins virtuelle Nirvana. Eine Initialisierung sehe ich jedenfalls nirgens. So ist's besser:
USHORT ValueCapsLength; ValueCapsLength = HID_CAPS.OutputReportByteLength; HIDP_VALUE_CAPS* pValueCaps = new HIDP_VALUE_CAPS[ValueCapsLength]; HidP_GetValueCaps(HidP_Input, pValueCaps, &ValueCapsLength, PreparsedData);
-
Es funktioniert fast. Meine Ausgabe ist nur noch nicht ganz korrekt.
Ich bekomme 0xCC oder 204 zurück.BYTE sendstring[261] = {0x00, 0x10, 0x83, 0x00, 0x49, 0xCC, 0x16}; BYTE getstring[261]; WriteFile(hTreiber, sendstring, 261, &BytesWritten, NULL); printf("WriteFile, Error: %u\n", GetLastError()); SetLastError(0); ReadFile(hTreiber, getstring, 261, &BytesRead, NULL); printf("ReadFile, Error: %u\n", GetLastError()); printf("0x%X\n", getstring[261]);
GetLastError() bringt genau das, was Du gesagt hast.
Ich hab gerade Deinen Vorschlag probiert, ist bestimmt bloß'n Schreibfehler, oder?-King- schrieb:
USHORT ValueCapsLength; ValueCapsLength = HID_CAPS.OutputReportByteLength;
Das müsste doch so heißen:
ValueCapsLength = HIDP_CAPS.OutputReportByteLength;
Da kommt bei mir aber der Fehler:
error C2275: "HIDP_CAPS" : Ungültige Verwendung dieses Typs als Ausdruck
-
baschti schrieb:
Ich bekomme 0xCC oder 204 zurück.
Von wem oder was?
baschti schrieb:
WriteFile(hTreiber, sendstring, 261, &BytesWritten, NULL); printf("WriteFile, Error: %u\n", GetLastError());
Das darfst Du so auf gar keinen Fall machen. Nach der Rückkehr von WriteFile kann GetLastError alles zurückgeben. Von Bedeutung ist das aber erst dann, wenn WriteFile auch tatsächlich fehlgeschlagen ist. Das mußt Du also prüfen, bevor Du GetLastError anwendest. Das gilt übrigens ebenso für ReadFile.
Von dieser Regel gibt's natürlich auch Ausnahmen. Als Beispiel sei hier CreateMutex genannt. Hier gibt GetLastError auch nach einem erfolgreichen Aufruf einen sinnigen Wert zurück. Das ist aber eine Ausnahme(!), und diese ist dann als solche extra dokumentiert.
Ich hab gerade Deinen Vorschlag probiert, ist bestimmt bloß'n Schreibfehler, oder?
Klar.
Da kommt bei mir aber der Fehler:
Bitte? Aber natürlich ist das ein Fehler. Ich wollte doch lediglich deutlich machen, daß der Wert aus der HIDP_CAPS-Struktur kommt. Aber eine Struktur-Instanz mußt Du noch erstellen. Also bitte:
HIDP_CAPS caps; // instanziieren HidP_GetCaps(pData, &caps); // füllen ValueCapsLength = caps.OutputReportByteLength;
Ich hoffe jedenfalls, daß Du mich damit nicht veralbern wolltest. Aber wenn Du gleich kommst und sagst, daß pData nicht bekannt ist, habe ich Gewissheit ...
-
Sorry, da hab' ich vorhin bei beiden geträumt. Langer Praktikumstag gewesen.
-King- schrieb:
baschti schrieb:
Ich bekomme 0xCC oder 204 zurück.
Von wem oder was?
Vom Adapter oder der SPS.
-
baschti schrieb:
Sorry, da hab' ich vorhin bei beiden geträumt. Langer Praktikumstag gewesen.
Ach, das ist das ganze Geheimnis. Dann bin ich beruhigt.
baschti schrieb:
Vom Adapter oder der SPS.
Aha. Wobei sich 0xCC eher nach einer nicht initialisierten Stack-Variable anhört, evetuell Aufgrund einer fehlgeschlagenen Funktion (die hätte initialisieren sollen). Ansonsten bin ich mir noch immer unklar darüber, ob die Werte nun gut oder schlecht sind. Und außerdem sind das 260 Bytes, die die SPS liefern sollte. Ein schlichtes 204 ist irgendwie ganz schön wenig ...
-
-King- schrieb:
Ein schlichtes 204 ist irgendwie ganz schön wenig ...
Habe ich mir auch so gedacht. Mal kucken, wo der Fehler liegt.
Ich danke Dir erstmal recht herzlich für Deine Hilfe.
-
Du hast mich falsch verstanden. Du übergibst doch einen Buffer mit einer Größe von 261 Byte. Davon wird jetzt ein Byte auf 0xCC gesetzt. Von welchem Byte reden wird denn nun? Und ist das jetzt gut oder schlecht? Betrifft das alle Bytes? Schlägt vielleicht ReadFile fehl (eine Prüfung hast Du ja noch nicht eingebaut)? Mit welchem Fehlercode schlägt ReadFile fehl, wenn überhaupt?
-
Mahlzeit!
Habe meine Fehler beseitigt. So, denke ich, funktionierts, da ja Write/ReadFile bei Misserfolg NULL zurückgeben:WriteFile(... if(WriteFile == 0) { CloseHandle(hTreiber); printf("Can't write to device."); printf("Error: %u\n", GetLastError()); } SetLastError(0) ReadFile(... if...
Beide schlagen bei mir demnach nicht fehl. Aber trotzdem stehe ich ein bisschen auf dem Schlauch. Ich würde sagen 0xCC ist der ReportID, aber wo muss er dann in der Anweisung stehen und warum empfange ich mit ReadFile immer 0xCC?
Das mit dem HidP_GetUsageValue habe ich jetzt so gemacht:
HIDP_VALUE_CAPS ValueCaps; PUSHORT ValueCapsLength; ValueCapsLength = &Capabilities.InputReportByteLength; HidP_GetValueCaps(HidP_Input, &ValueCaps, ValueCapsLength, PreparsedData); printf("%s0x%X\n", "Input - ReportID: ", ValueCaps.ReportID); . . .
Resultat:
Input - GetValueCaps: Input - ReportID: 0xCC Input - BitField: 0xCCCC Input - BitSize: 0xCCCC Input - LinkCollection: 0xCCCC Input - LinkUsage: 0xCCCC Input - LinkUsagePage: 0xCCCC Output - GetValueCaps: Output - ReportID: 0xCC Output - BitField: 0xCCCC Output - BitSize: 0xCCCC Output - LinkCollection: 0xCCCC Output - LinkUsage: 0xCCCC Output - LinkUsagePage: 0xCCCC
-
baschti schrieb:
WriteFile(... if(WriteFile == 0)
Da der Funktions-Pointer nicht NULL ist, wird hier Falle eines Fehlschlags niemals true rauskommen. Das geht so:
if(!WriteFile(...)) { // Fehlschlag }
Das Selbe gilt logischerweise auch für ReadFile. Der Aufruf von SetLastError ist an dieser Stelle zwar nicht schädlich, aber überflüssig.
baschti schrieb:
HIDP_VALUE_CAPS ValueCaps; PUSHORT ValueCapsLength; ValueCapsLength = &Capabilities.InputReportByteLength;
Und was ist nun der Inhalt von ValueCaps? Ist die Capabilities-Struktur korrekt gefüllt?
baschti schrieb:
HidP_GetValueCaps(HidP_Input, &ValueCaps, ValueCapsLength, PreparsedData); printf("%s0x%X\n", "Input - ReportID: ", ValueCaps.ReportID); . . .
Resultat:
Zum Resultat kann ich gern etwas sagen. Aber erstmal sagst Du mir, ob HidP_GetValueCaps fehlschlägt oder nicht (--> die Prüfung fehlt hier). Wenn wenn die Funktion fehlschlagen sollte: Was sagt GetLastError?
Außerdem darfst Du nicht einfach &ValueCaps schreiben. Da wird ein Array in der Größe ValueCapsLength erwartet, das passt bei Dir nur zufällig. In jeder anderen Anwendung kommt es hier zum Crash. Deswegen habe ich auch weiter oben new verwendet.
-
baschti schrieb:
ValueCapsLength = &Capabilities.InputReportByteLength;
Das ist natülich falsch! Wenn schon, dann so:
ValueCapsLength = &Capabilities.NumberInputValueCaps;
Das habe ich leider im Eifer des Gefechts weiter oben bereits falsch vorgemacht. Sorry!
-
Hab's jetzt mal so gemacht, wie Du's gesagt hast:
HIDP_CAPS Capabilities; PHIDP_PREPARSED_DATA PreparsedData; HIDP_REPORT_TYPE HidP_Input; USHORT ValueCapsLength; HIDP_VALUE_CAPS* pValueCaps = new HIDP_VALUE_CAPS[ValueCapsLength]; . . . HidD_GetPreparsedData(hTreiber, &PreparsedData); HidP_GetCaps(PreparsedData, &Capabilities); printf("%s%d\n", "Usage: ", Capabilities.Usage); printf("%s0x%X\n", "Usage Page: ", Capabilities.UsagePage); printf("%s%d\n", "Input Report Byte Length: ", Capabilities.InputReportByteLength); . . . ValueCapsLength = Capabilities.NumberInputValueCaps; printf("Input - GetValueCaps:\n\n"); if(!HidP_GetValueCaps(HidP_Input, pValueCaps, &ValueCapsLength, PreparsedData)) { CloseHandle(hTreiber); printf("Error: %u\n", GetLastError()); } printf("ValueCaps: 0x%X\n", pValueCaps); printf("%s0x%X\n", "Input - ReportID: ", pValueCaps.ReportID);
nur bekomme ich jetzt den Fehler:
error C2228: Der linke Teil von '.ReportID' muss eine Klasse/Struktur/Union sein
Wenn ich die letzte Anweisung auskommentiere, bekomme ich für
pValueCaps: 0x431D40
und keinen Fehler über GetLastError().
Vorhin dachte ich, das wäre schon die gefüllte ValueCaps-Struktur:baschti schrieb:
Resultat:
Input - GetValueCaps: Input - ReportID: 0xCC Input - BitField: 0xCCCC Input - BitSize: 0xCCCC Input - LinkCollection: 0xCCCC Input - LinkUsage: 0xCCCC Input - LinkUsagePage: 0xCCCC Output - GetValueCaps: Output - ReportID: 0xCC Output - BitField: 0xCCCC Output - BitSize: 0xCCCC Output - LinkCollection: 0xCCCC Output - LinkUsage: 0xCCCC Output - LinkUsagePage: 0xCCCC
Ich verzweifle gleich!
-
baschti schrieb:
nur bekomme ich jetzt den Fehler:
error C2228: Der linke Teil von '.ReportID' muss eine Klasse/Struktur/Union sein
Hast den Begriff Pointer schon mal gehört? Hast Du new überhaupt schon mal benutzt?
printf("%s0x%X\n", "Input - ReportID: ", pValueCaps->ReportID);
Und da es sich um ein Array handelt, kannst Du das auch so machen:
printf("%s0x%X\n", "Input - ReportID: ", pValueCaps[i].ReportID);
Für i gilt:
0 <= i < Capabilities.NumberValueCaps
Und bevor Du wieder mit mir schimpfst: Bewusst schrieb ich nur NumberValueCaps. Je nach gewünschtem Report verwendest Du natürlich Number -Input/ Output/ Feature - ValueCaps.
BTW: Es scheint mir angebracht, auch auf delete hinzuweisen. Wenn Du also mit den HIDP_VALUE_CAPS-Structs fertig bist, Freigabe nicht vergessen:
delete [] pValueCaps;
-
Ich gelobe Besserung. Hab' manchmal Probleme mich zurecht zu finden.
ok?Input - GetValueCaps: ValueCaps: 0x431D90 Input - ReportID: 0xFD Input - BitField: 0x0 Input - BitSize: 0x43 Input - LinkCollection: 0x0 Input - LinkUsage: 0x31 Input - LinkUsagePage: 0x0
Output - GetValueCaps: ValueCaps: 0x431D90 Output - ReportID: 0xFD Output - BitField: 0x0 Output - BitSize: 0x43 Output - LinkCollection: 0x0 Output - LinkUsage: 0x31 Output - LinkUsagePage: 0x0
Kannst Du mir bitte noch was zum Resultat sagen, was Du vorhin angesprochen hast, was ich jetzt damit anfange? Danke
Ich glaube, ich brauche echt erstmal Urlaub.
-
Mit diesem Resultat kannst Du gar nicht anfangen. Alle Werte auf 0xCD sagen nicht so sehr viel aus. Da stimmt noch etwas nicht.
BTW: Die HidP_-Funktionen geben einen Status-Code direkt zurück. So, wie es auch in der Hilfe beschrieben steht. Du kannst nicht einfach mit if(!HidP_ auf Fehlschlag testen.
NTSTATUS stat; stat = HidP_GetValueCaps(...); if(HIDP_STATUS_SUCCESS == stat) { // Ok } else { printf("Error: 0x%08X\n", stat); }
-
Habe meinen Fehler gefunden, schau nochmal bitte, hab's weiter oben editiert.
-
Ist ReportCount = 6 und IsRange = TRUE? Ist 0xFD als ReportID tatsächlich richtig (kannst mit Deinem Sniffer schauen, was das Gerät auf den GET_REPORT Request antwortet)? Irgendwie sieht das doch anders aus, als ich es erwartet hätte. Vielleicht kannst Du noch ein paar andere Felder der Struktur aufdröseln.
Was ist denn jetzt eigentlich aus den ReadFile/ WriteFile-Aufrufen geworden, funktionieren die jetzt?