Moin Leute,
ich suche eine Programmiersprache, welche bereits Komponenten für die
USB-HID-Kommunikation unter Windows beinhaltet und eine einfache
GUI-Schnittstelle bietet.
Nach Möglichkeit soll es keine Interpreter-Sprache sein, schon gar nicht
JAVA!
Am liebesten wäre mir eine finale .exe-Datei ohne Installationsmonster.
Kann hier jemand eine solche Sprache empfehlen, mit der er ohne
Schwierigkeiten eine Windows-GUI-Anwendung mit USB-HID-Kommunikation
programmiert hat?
Danke!
Backspace schrieb:> für die> USB-HID-Kommunikation unter Windows beinhaltet
Das Gerät wird wie eine Datei geöffnet und die normalen
open/read/write/close Funktionen können verwendet werden. Das geht in
jeder Programmiersprache.
Das umständliche Part ist eigentlich nur den Dateinamen für ein
gegebenes Gerät zu finden bzw. vorhandene Geräte aufzulisten, dafür
gibts aber API-Funktionen (Stichwort SetupAPI) und Beipielcode im Netz.
C#? Das ist C in etwas billiger mit framework und gratis IDE vom
Fensterbauer.
Sonst halt Borland Delphi. Aber das hängt stark an den Fähigkeiten mit
PASCAL.
Sonst halt C. Aber das hängt stark am Umgang mit den GUI Dingern.
Sonst halt Fortran. Aber das hängt stark an Fortran.
Interessant wäre, was du schon kannst.
Bernd K. schrieb:> Das Gerät wird wie eine Datei geöffnet und die normalen> read/write-Funktionen können verwendet werden. Das geht in jeder> Programmiersprache.
Ja, das ist mir schon klar, das geht sogar mit JAVA.
Mit jeder Sprache ist ja auch eine GUI möglich.
Aber das beantwortet überhaupt nicht meine Frage zu einer Empfehlung
nach den oben genannten Kriterien!
Also bevor die Dikussion sich hier am Thema vorbei entwickelt,
wiederhole ich am besten nochmal den Abschlussatz aus meinem
Eingangspost, wobei der Text davor gerne auch gelesen werden darf:
Kann hier jemand eine solche Sprache empfehlen, mit der er ohne
Schwierigkeiten eine Windows-GUI-Anwendung mit USB-HID-Kommunikation
programmiert hat?
testfall schrieb:> C#? Das ist C in etwas billiger mit framework und gratis IDE vom> Fensterbauer.>> Sonst halt Borland Delphi. Aber das hängt stark an den Fähigkeiten mit> PASCAL.>> Sonst halt C. Aber das hängt stark am Umgang mit den GUI Dingern.>> Sonst halt Fortran. Aber das hängt stark an Fortran.>> Interessant wäre, was du schon kannst.
Danke testfall!
Ich habe Erfahrung in C nur auf µC-Ebene.
Sonst Java und vor allem Pascal. Aber gibt es in Lazarus oder Delphi
eine einfache USB-HID-Komponente? Ich will ja das Rad nicht neu erfinden
und zum Wrapper-König mutieren, sondern nur möglichst schnell ein
simples Ergebnis bekommen.
In Delphi wäre zumindest die Generierung einer single-exe Date gegeben
aber USB-technisch kenne ich da nichts.
Ich setze mich auch gerne mit neuen Sprachen auseinander.
Backspace schrieb:> Aber gibt es in Lazarus oder Delphi> eine einfache USB-HID-Komponente? Ich will ja das Rad nicht neu erfinden> und zum Wrapper-König mutieren, sondern nur möglichst schnell ein> simples Ergebnis bekommen.
Ich benutze unter Delphi die Jedi Componenten, dort ist HID auch drinne
Bernd K. schrieb:> Hier sind ein paar Pascal Codeschnipsel von mir:
Danke Bernd!
Dann nützt du offensichtlich eine Jedi-Komponente.
Das schaue ich mir an!
Backspace schrieb:> Bernd K. schrieb:>> Hier sind ein paar Pascal Codeschnipsel von mir:>> Danke Bernd!> Dann nützt du offensichtlich eine Jedi-Komponente.> Das schaue ich mir an!
Ich hab mir die paar API-Funktionen die nötig sind aus dem Jedi-API
extrahiert in ne eigene Unit, siehe Anhang (vier Funktionen der
SetupAPI.dll und ein kleiner Stall voll zugehöriger Typdeklarationen).
Dieser Zinnober wird nur benötigt um die Geräte aufzuzählen und das
Gerät das einen interessiert rauszufiltern (meine Enumerate-methode),
sobald Du den Dateinamen hast gehts ganz normal mit FileOpen, FileRead
und FileWrite weiter.
Nur eins muß man beachten: Der gererische Windows HID-Treiber hat einen
Bug: Wenn ein Thread blockierend in der FileRead hängt darf ein anderer
Thread nicht FileWrite aufrufen. Deshalb der Tanz mit dem Mutex und
CancelIoEx.
Bernd K. schrieb:> Ich hab mir die paar API-Funktionen die nötig sind aus dem Jedi-API> extrahiert in ne eigene Unit, siehe Anhang (vier Funktionen der> SetupAPI.dll und ein kleiner Stall voll zugehöriger Typdeklarationen).
Das ist interessant!
Offenbar bist Du da sehr versiert. Das hilft mir in jedem Fall.
Vermutlich werde ich mich dann doch wieder mit Delphi beschäftigen.
Bernd K. schrieb:> Dieser Zinnober wird nur benötigt um die Geräte aufzuzählen und das> Gerät das einen interessiert rauszufiltern (meine Enumerate-methode),> sobald Du den Dateinamen hast gehts ganz normal mit FileOpen, FileRead> und FileWrite weiter.>> Nur eins muß man beachten: Der gererische Windows HID-Treiber hat einen> Bug: Wenn ein Thread blockierend in der FileRead hängt darf ein anderer> Thread nicht FileWrite aufrufen. Deshalb der Tanz mit dem Mutex und> CancelIoEx.
O.k. habe ich im Prinzip verstanden.
Coole Infos und mein Respekt!
Vielen Dank Bernd!
Backspace schrieb:> Kann hier jemand eine solche Sprache empfehlen, mit der er ohne> Schwierigkeiten eine Windows-GUI-Anwendung mit USB-HID-Kommunikation> programmiert hat?
VB.net
C#
Delphi/OP
Lazarus/FP
C
C++
In allen diesen Sprachen habe ich das schon getan. Ich befürchte nur:
diese Auskunft hilft dir kein bissel weiter, denn das Kernproblem ist
ganz offensichtlich nicht die Programmiersprache...
c-hater schrieb:> Ich befürchte nur:> diese Auskunft hilft dir kein bissel weiter, denn das Kernproblem ist> ganz offensichtlich nicht die Programmiersprache...
Du hast Recht. Deine Aussage hilft mir null, da diese mit "geht mit
allen Programmiersprachen" gleichzusetzen ist und offenbar nur der
eigenen Beiweihräucherung dient.
Ich habe das bislang mit Java gemacht und will aus mehreren Gründen
wechseln.
Dir zu Liebe würde ich ja eine C-Sprache nehmen - aber befasse mich nun
doch nochmal mit Delphi oder auch Lazarus, nachdem es auch sinnvolle
Beiträge hier gab.
Backspace schrieb:> Dir zu Liebe würde ich ja eine C-Sprache nehmen - aber befasse mich nun> doch nochmal mit Delphi oder auch Lazarus, nachdem es auch sinnvolle> Beiträge hier gab.
C++Builder in der Community Edition. C++ inkl. aller Libs (fast, ab der
10.3 unterstützen einige der mitgelieferten Compiler C++17 andere aber
nur C++11) und alle Delphi-Komponenten lassen sich verwenden.
Arc N. schrieb:> C++Builder in der Community Edition. C++ inkl. aller Libs (fast, ab der> 10.3 unterstützen einige der mitgelieferten Compiler C++17 andere aber> nur C++11) und alle Delphi-Komponenten lassen sich verwenden.
Auch interessant aber warum sollte ich dann den Umweg über C++ machen?
Gerade für C und Konsorten hätte ich gedacht, dass es nur so wimmelt von
USB-Komponenten.
Ich werde am WE mal den Weg von Bernd K. mit Lazarus ausprobieren.
Bernd K. schrieb:> Hier sind ein paar Pascal Codeschnipsel von mir:
Sorry, ich habe da nochmal eine dumme Frage:
Ich habe Deine Fragmente mal so in Lazarus eingesetzt und natürlich
fehlt da noch das ein oder andere.
Woher z.B. hast Du die Konstantenwerte wie z.B. "USB_CLASS".
Finde ich diese in den Jedi-Komponenten?
Dankeschön vorab für eine kurze Erleuchtung!
Backspace schrieb:> Bernd K. schrieb:>> Hier sind ein paar Pascal Codeschnipsel von mir:>> Sorry, ich habe da nochmal eine dumme Frage:>> Ich habe Deine Fragmente mal so in Lazarus eingesetzt und natürlich> fehlt da noch das ein oder andere.>> Woher z.B. hast Du die Konstantenwerte wie z.B. "USB_CLASS".>> Finde ich diese in den Jedi-Komponenten?> Dankeschön vorab für eine kurze Erleuchtung!
Das ist die Klasse für HID-Geräte.
Sorry, die Code-Schnipsel sind aus nem größeren Projekt, die Komponente
aus der ich die Methoden gepostet habe abstrahiert ein proprietäres
HID-Gerät mit allerlei Spezialfunktionen, deshalb wollte ich nur das
Zeug posten das allgemeingültig ist und nicht die ganze Unit. Wenn noch
mehr fehlt, sage bitte Bescheid, ich reiche es nach.
Bernd K. schrieb:> Wenn noch> mehr fehlt, sage bitte Bescheid, ich reiche es nach.
Genial Meister!
Wenn ich dann so unverschämt sein darf, es fehlen mir noch die
Definitionen für:
"FDevice"
"StartThreads"
"DriverReadWriteMutex"
Danke :)
Backspace schrieb:> Bernd K. schrieb:>> Wenn noch>> mehr fehlt, sage bitte Bescheid, ich reiche es nach.>> Genial Meister!>> Wenn ich dann so unverschämt sein darf, es fehlen mir noch die> Definitionen für:>> "FDevice"> "StartThreads"> "DriverReadWriteMutex">> Danke :)
1
uses
2
syncobjs;
1
FDevice: THandle;
2
DriverReadWriteMutex: TCriticalSection;
1
constructor TLazHid.Create(AOwner: TComponent);
2
begin
3
inherited Create(AOwner);
4
DriverReadWriteMutex := TCriticalSection.Create;
5
6
// noch mehr
1
destructor TLazHid.Destroy;
2
begin
3
// einiges andere
4
5
DriverReadWriteMutex.Free;
6
inherited Destroy;
7
end;
Und StartThreads ist nur eine Methode die ein paar Threads startet die
den anderen Klimbim steuern, Sachen die sich mit den speziellen
Vorgängen bei diesem einen Gerät beschäftigen die ich nicht gepostet
habe.
Letztendlich starte ich da unter anderem einen Thread der nichts weiter
macht als dann in einer Schleife die meiste Zeit lang in der schon
geposteten DeviceReadReport Methode blockierend auf eingehende
HID-Reports zu warten (und die dann zu sortieren und in verschiedene
Queues zu stopfen) so lange bis das Handle durch irgendwas wieder
geschlossen wurde. Und noch ein paar andere Threads die andere ganz
spezielle Dinge tun die nur mit der speziellen Funktion dieses Gerätes
zu tun haben.
Und was die 64 oder 65 Byte in DeviceReadReport angeht:
Das spezielle Gerät das ich da habe sendet und empfängt HID-Reports der
Länge 64, das ist so in dessen Device-Descriptor festgelegt, das ist die
Maximallänge die bei HID in einem Rutsch transferiert werden kann und
bei dem Gerät nutze ich die voll aus.
Die FileRead() Funktion des generischen Windows HID Treibers wird NUR
dann funktionieren wenn der übergebene Buffer genau die Länge des
Reports plus 1 hat, man kann im Gegensatz zu Linux (libhidapi) immer nur
den ganzen Report in einem Rutsch auslesen und es ist immer die
Report-ID als erstes Byte vorangestellt und wen der Puffer kleiner (oder
größer) ist kommt kommentarlos gar nichts! Da hab ich ne Weile dran
geknabbert denn das hab ich in keiner Dokumentation gefunden (oder nicht
richtig gesucht).
Wenn also Dein Gerät kleinere Reports verschickt und nichts kommt dann
probier da auch mal nen entsprechend kleineren Empfangspuffer zu
übergeben.
Wenn Du übrigens ne Lösung für Linux brauchst hab ich ein
objektorientiertes Pascal-Binding für libhidapi geschrieben:
https://github.com/prof7bit/HIDAPI.pas
Lizenz: LGPL mit static linking exception
(Dazu muss das Paket libhidapi-dev installiert sein sonst meckert der
Linker. Auf der Zielmaschine brauchst Du nur libhidapi-libusb0 und
natürlich eine passende udev-Regel damit der Nutzer Berechtigung für das
Gerät bekommt)
Vielen Dank Bernd!
Ich nutze ohnehin die volle Länge von 64 Byte, von daher passt das
natürlich optimal. Auf die 65 wäre ich da natürlich nicht gekommen...
Auf Deine github-Seite bin ich auch schon gestossen, da habe ich
offenbar den Vollprofi erwischt!
So tief möchte ich gar nicht einsteigen (auch wenn es sicherlich sehr
lehrreich wäre).
Leider bin ich nur in der WindowsWelt zu Hause - aber sag niemals nie.
Deine Codefragmente compilieren zumindest jetzt fehlerfrei.
Ich hoffe, mich noch heute oder am WE damit beschäftigen zu können.
Die Vorgehensweise wird vermutlich sein:
1. Enumerate(Vid: Word; Pid: Word; List: TStringList);
dann bekomme ich wahrscheinlich eine Liste mit allen Devices und kann da
die zugehörige ID meines Devices auslesen.
Mit diesem (meinem) extrahierten String rufe ich dann
2. Open(Path: String);
und sollte dann meine Reports lesen und schreiben können.
Beim Lesen ist mir gleich aufgefallen, dass ich einen Käse geschrieben
habe.
Ich rufe die Enummerierung natürlich mit meiner VID und PID auf.
Was der letzte Parameter, die Stringliste bedeutet erschließt sich mir
noch nicht, kommt aber sicher noch.
Also wird die Reihenfolge irgendwie anders sein - aber da komme ich
sicher drauf.
Naja, wenn ich Delphi Komponenten verwenden will und Delphi nutzen kann,
warum dann einen Umweg über C++ nehmen?
> C++Builder in der Community Edition. C++ inkl. aller Libs (fast, ab der> 10.3 unterstützen einige der mitgelieferten Compiler C++17 andere aber> nur C++11) und alle Delphi-Komponenten lassen sich verwenden.
Backspace schrieb:> Was der letzte Parameter, die Stringliste bedeutet erschließt sich mir> noch nicht, kommt aber sicher noch.
Du erzeugst erst eine leere TStringList Instanz und übergibst sie der
Enumerate() Methode. Wenn die Methode dann zurückkehrt beinhaltet diese
Liste (hoffentlich) mindestens ein Element welches der Pfadname ist den
Du direkt für die Open() methode verwendest. Wenn sie mehr als ein
Element enthält waren mehrere der Geräte mit VID und PID angeschlossen
ud Du könntest sie alle einzeln öffnen oder nur das erste oder was auch
immer. Man könnte die Enumerate-Methode theoretisch auch noch aufbohren
so daß man nach der Seriennummer filtern kann oder evtl auch so daß sie
alle Seriennummern passender Geräte zurückliefert aber das war bei
meiner Anwendung nicht nötig. Sobald Du den Pfadnamen hast kannst Du die
Stringliste wieder zerstören wenn Du sie nicht mehr anderweitig
brauchst.
Ich wollte nur nochmal sagen DANKE Bernd !!!
Dank Deiner genial simplen vorgekauten Lösung konnte ich in Lazarus nach
kurzer Zeit schon Reports senden und empfangen.
Wirklich Wahnsinn, wie einfach das dank Deiner Hilfe ging!
Die Hauptschwierigkeit war dann nur, das geschundene Hirn wieder vom
Java-Slang auf Pascal umzubiegen.
Jetzt muss ich mich noch ein wenig in der setupAPI nach den Methoden
umschauen, um die Seriennummer, den manufacturer und product string und
was mich sonst noch so interessiert, zu extrahieren.
Ich trinke heute Abend ein Bier auf Dich!