USB-Port ansprechen



  • 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?



  • Ich gehe Deinen Fragen gleich mal nach. Was für Werte hättest Du erwartet?

    War vorhin in der MSDN zu NTSTATUS, habe dort leider nur die Bereiche für Fehler, Erfolge, Informationen,... gefunden. Gibt es da eine Auflistung der Fehler?

    Ich habe meine printf-Anweisungen der VALUE_CAPS-Struktur in die if-Schleife geschrieben und komischerweise einen Fehler 0xC0110222 (oder so ähnlich) bekommen. Hatte ValueCapsLength zunächst mit 0 initialisiert.

    ReadFile gibt immer noch 0xCC zurück, obwohl kein Fehler kommt.



  • baschti schrieb:

    Ich gehe Deinen Fragen gleich mal nach. Was für Werte hättest Du erwartet?

    Jedenfalls andere. Einmal 43 Bit passen nicht so richtig zu einer Report-Länge von 261 Bytes, jedenfalls für meinen Geschmack.

    baschti schrieb:

    War vorhin in der MSDN zu NTSTATUS, habe dort leider nur die Bereiche für Fehler, Erfolge, Informationen,... gefunden. Gibt es da eine Auflistung der Fehler?

    Gültige Werte stehen in der Hilfe. Wenn Du Dir beispielsweise mal bei HidP_GetValueCaps den 'Return Value' anschaust:

    MSDN schrieb:

    HidP_GetValueCaps returns one of the following status values.

    HIDP_STATUS_SUCCESS
    - The routine successfully returned the capability data.

    HIDP_STATUS_INVALID_PREPARSED_DATA
    - The preparsed data is not valid.

    Die komplette Auflistung findest Du in <hidpi.h>.

    baschti schrieb:

    Ich habe meine printf-Anweisungen der VALUE_CAPS-Struktur in die if-Schleife geschrieben und komischerweise einen Fehler 0xC0110222 (oder so ähnlich) bekommen. Hatte ValueCapsLength zunächst mit 0 initialisiert.

    Ich tippe auf 'oder so ähnlich'. Aber davon ab: Du sagst der Funktion, daß Du ein Array in der Größe 0 übergibst. Deswegen füllt die Funktion nun 0 Strukturen. Wenn die Funktion zurückkehrt, ändert sie ValueCapsLength auf die tatsächlich ausgefüllten Strukturen. Es muß 0 bleiben, es ist auch rein gar nichts passiert (wie auch?).

    Und bitte sage nicht 'if-Schleife'. Da zieht sich alles zusammen, das ist doch keine Schleife. 😉

    baschti schrieb:

    ReadFile gibt immer noch 0xCC zurück, obwohl kein Fehler kommt.

    Als direkten Return-Value, ja? Dann schauen wir doch schnell mal in die Hilfe zu ReadFile und lesen, was dort unter 'Return Values' steht:

    MSDN schrieb:

    If the function succeeds, the return value is nonzero.

    Es hat funktioniert! Du hast erfolgreich Daten vom Gerät empfangen. Dann nehme ich an, daß Du auch erfolgreich Daten an das Gerät senden kannst, ja?



  • -King- schrieb:

    Und bitte sage nicht 'if-Schleife'. Da zieht sich alles zusammen, das ist doch keine Schleife. 😉

    uarghhh... 😡 , dafür kannst Du mich steinigen. Ist mir beim Schreiben nicht aufgefallen - if-Anweisung.

    Danke für die Tips. 🙂 Ich setze das gleich mal um. Tut mir leid, wenn das von mir manchmal nicht so perfekt rüberkommt.
    Bevor ich ins Praktikum gekommen bin, hatte ich eher ein beschränktes Wissen über hardwarenahe Programmierung und nie gedacht, dass mir das soviel Spass macht und ich doch relativ weit bisher gekommen bin, auch Dank Deiner Hilfe. 👍 (Obwohl manchmal bei mir trotzdem einer auf der Leitung steht 💡)


Anmelden zum Antworten