Forum: PC-Programmierung USB in VB oder VC++


von Ralf (Gast)


Lesenswert?

Hallo,

es geht mal wieder um USB aus VB oder VC++. Hab ein paar Fragen, die
ich trotz Suche im Forum leider beantworten konnte. Oder ich bin zu
blöd zum Suchen.

1. Gibt es eine universelle DLL bzw. ein universelles Objekt, ähnlich
dem COM-Port-Objekt aus VB, mit dem man auf USB zugreifen kann? Frei
verfügbar natürlich, denn dass es das in "teuer" gibt, weiss ich
latürnich!!!
2. Falls 1. verneint werden muss, gibt es die Möglichkeit, über die
WinAPI auf USB zuzugreifen? Wenn ja, wie? Links erwünscht!

Danke!

Ralf

von René K. (king)


Lesenswert?

1. Nein, gibt es nicht. Allerdings gibt es Bausteine von SiLabs,
Profilic oder FTDI, die Dir die normale serielle Schnittstelle
nachbilden. Auch gibt es für diese Chips eigene APIs zur Kommunikation
vom Hertsller.

2. Über API geht das natürlich. Das geht sogar ganz genau so, wie das
mit der normalen Seriellen auch geht: CreateFile, ReadFile, WriteFile,
DeviceIoControl und CloseHandle. Wie Du die drei mittigen Funktionen
anwendest, ist abhängig vom verwendeten Gerät.

Sofern Du noch etwas mehr mit dem USB vorhast, kann ich nur dringend
raten, ein Buch zu lesen. Jan Axelson hat in seinem 'Handbuch für
Entwickler' übrigens auch einige Beispiele für VB und VC.

von Thomas S. (tstuetz)


Lesenswert?

zu 1: KERNEL32.DLL :-)
zu 2: Das USB Gerät verwenden wie eine Datei:

=> CreateFile(),ReadFile(),WriteFile(),CloseHandle()

Das Größte Problem dabei ist den entsprechenden
"Dateinamen"=Symbolic-Link zu finden.

=> SetupDi* Funktionen aus der setupapi.dll/lib

Je nach Endpunkt (Lesen/Schreiben) im USB-Gerät gibt es dann
verschiedene "PIPE"s ("PIPE00"/"PIPE01").

Gruss

von René K. (king)


Lesenswert?

> Je nach Endpunkt (Lesen/Schreiben) im USB-Gerät gibt es dann
> verschiedene "PIPE"s ("PIPE00"/"PIPE01").

Aus der Sicht des Anwenders stimmt das so nicht. Die Quelle oder das
Ziel der Daten bestimmt einzig und allein der Treiber.

von Thomas S. (tstuetz)


Lesenswert?

@King Stimmt, also darauf achten welches PIPE<xx> für lesen und
schreiben verwendet werden muß.

Fällt mir gerade ein - ohne PIPE kann der Endpunkt 0 = Controlkanal
angesprochen werden.

Gruss

von René K. (king)


Lesenswert?

Man muß darauf achten, welchen Treiber man verwendet. Ich habe hier zum
Beispiel einen Treiber, der ganz ohne Angabe einer Pipe EP3 zum
Schreiben/ Lesen verwendet (das weiß ich deswegen so genau, weil
Treiber und Gerät von mir sind).

von René K. (king)


Lesenswert?

Ach ja, bei HIDs habe ich auch noch nie mit PIPEs 'gefummelt'.
Trotzdem wird von EP1 gelesen und auf EP2 geschrieben.

von Ralf (Gast)


Lesenswert?

Erstmal danke für die Beiträge. Hätte nicht gedacht, dass in so kurzer
Zeit so viele zusammenkommen grins

Okay, also über API. Muss ich mir erstmal beibringen. Ist das arg
schwer?!?

@René:
Kannst du deinen Code hier posten?

Ralf

von Weinga-Unity (Gast)


Lesenswert?

Hi!

Windows macht USB nur kompliziert und es existiert doch eine einfache
Möglichkeit, USB-Geräte zu verwalten:

Die Bibliothek heißt LIBUSB und ist für mehrere Betriebssysteme
erhältlich (auch WIN32). Mit nem beiliegenden Tool generiert man
einfach nen eigenen Treiber (.ini) für das entsprechende Gerät und
lässt das Gerät mit den neuen Treiber laufen. Mit der C-Bibliothek oder
ner DLL stehen alle USB-Funktionen zur Verfügung (Lesen schreiben auf
Endpoints, Descriptoren, ...).

Hab auch vor kurzen so ein Projekt durchgeführt welches unter
www.ime.jku.at/tusb publiziert ist (Vermerk auf die Doku bzw.
Präsentation).

Hoffe, ich konnte etwas helfen

mfg Weichinger Klaus
www.weinga-unity.at.tt

von Weinga-Unity (Gast)


Lesenswert?

PS: LIBUSB ist natürlich opensource und gibts irgendwo bei sourceforge

von JoeSeil (Gast)


Lesenswert?

Es hätte ja alles so einfach sein können.
Ich habe auch versucht ein HID Device anzusprechen, mit den oben
genannten Funktionen. Allerdings habe ich da ein paar Probleme.

1. Mein Device wird ordnungsgemäß gefunden. Es wird auch ein gültiger
Handle mit CreateFile erzeugt.

2. WriteFile() und ReadFile schlägt fehl. Fehler 1784: Der angegebene
Benutzerpuffer ist für den Vorgang ungültig???

unsigned char buffer[]={0,'e','s','t','T','e','s','t'};;
unsigned long num;
WriteFile(handle,buffer,8,&num,NULL));

Was kann das sein?

von René K. (king)


Lesenswert?

> Es hätte ja alles so einfach sein können.

Es ist so einfach.

> Was kann das sein?

Der Länge des Puffers, den Du zu schreiben versuchst, stimmt nicht mit
der tatsächlichen Länge überein. Die Längen müssen exakt stimmen. Bei
Reports, die einen Identifier benötigen, ist das Länge + 1.

Wie sieht denn der überhaupt InputReport-Descriptor aus?

von René K. (king)


Lesenswert?

> Wie sieht denn der überhaupt InputReport-Descriptor aus?

Da Du Daten zum Gerät übertragen möchtest, muß aus "Input"
logischerweise "Output" werden.

von JoeSeil (Gast)


Lesenswert?

also das mit dem WriteFile habe ich inzwischen hinbekommen. Es lag
wirklich an der Puffergröße, aber bei Readfile haberts noch.
Hier ist also der Report Descriptor. Den habe ich mir aus verschiedenen
App-Notes, vor allem aber aus der Projektarbeit von Klaus Weichinger
(sehr Aufschlussreich, siehe oben) zusammengestellt:

  usb_configuration =
  {
    { 9, CONFIGURATION, CONF_LENGTH, NB_INTERFACE, CONF_NB,
      CONF_INDEX, CONF_ATTRIBUTES, MAX_POWER},
    { 9, INTERFACE, INTERFACE_NB, ALTERNATE, NB_ENDPOINT,
INTERFACE_CLASS,
      INTERFACE_SUB_CLASS, INTERFACE_PROTOCOL, INTERFACE_INDEX },
    { 9, HID, 0x1101, 0, 1, REPORT, 0x2e00 },
    { 7, ENDPOINT, ENDPOINT_NB_1, EP_ATTRIBUTES_1, EP_SIZE_1,
EP_INTERVAL_1 },
    { 0x06,0xA0, 0xFF,    /* Usage Page (User Defined)   */
      0x09,0xA5,          /* Usage (Vendor defined)      */
      0xA1,0x01,          /* Collection (Application)    */
      0x09,0xa6,
      // Input Report
      0x09,0xA7,
      0x15,0x80,          /* Logical Minimum (-128)     */
      0x25,0x7F,          /* Logical Maximum (127)      */
      0x75,0x08,          /* Report Size (8 bit)        */
      0x95,0x08,          /* Report Count (8 byte)      */
      0x81,0x02,          /* Input (Data, Variable, Absolute)  */

      // output report
      0x09, 0xA9,
      0x15,0x80,          /* Logical Minimum (-128)    */
      0x25,0x7F,          /* Logical Maximum (127)    */
      0x75,0x08,          /* Report Size (8 bit)     */
      0x95,0x08,          /* Report Count (8 byte)   */
      0x91,0x08,          /* Output (Data, Variable,  */
     // Feature report
      0x09, 0xAA,
      0x15,0x80,          /* Logical Minimum (-128)       */
      0x25,0x7F,          /* Logical Maximum (127)    */
      0x75,0x08,          /* Report Size (8 bit)     */
      0x95,0x08,          /* Report Count (8 byte)        */
      0xB1,0x02,          /* Output (Data, Variable,        */
      0xC0                /* End Collection           */
      }

Ich habe einen Interrupt In Endpoint 1, der alle 10ms abgefragt werden
sollte (was aber anscheinend auch nicht gemacht wird).
Ein Aufruf wie folgt:

  unsigned char buffer[10]={0,'e','s','t'};;
  unsigned long num;
  ReadFile(m_HIDComm.HidHandle,buffer,10,&num,NULL);

verschwindet im Nirvana, es werden keine Daten gelesen. Es wird aber
auch keine Anforderung an den MC gesendet.
Ist das korrekt so?

Wenn ich also ein Readfile Request, bekomme ich keinen Fehler.
Allerding habe ich den Puffer auf 10 (8+ 2 Bytes) gesetzt, sonst kam
der bekannte Fehler 1784.

Was ist da komisch?
Beste Grüße Joerg

von René K. (king)


Lesenswert?

So, wie ich das sehe, benötigst Du einen Buffer der Größe 8+1 Byte. Das
erste Byte muß dabei vor dem Lesen genullt werden.

Wie groß der Buffer tatsächlich zu sein hat, erfährst Du übrigens von
HidP_GetCaps.

BTW: Das Abfragen alle 10 ms funktioniert auch ohne das eine Anwendung
läuft, die das Gerät bedient; das geht ganz und gar ohne Dein Zutun.
Für mich hört sich das im Momement an, als hättest Du noch einen dicken
Bock in Deiner Firmware. Um sicherzugehen, solltest Du auf alle Fälle
einen Protokoll-Analyzer zu Hilfe nehmen. Dann siehst Du sofort, was da
passiert. Da Du über die Enumeration bereits hinaus bist, sollten auch
die reinen Software-Lösungen taugen. Allerdings kann ich da nichts
empfehlen, da ich die selber nicht verwende (mir steht ein in Hardware
gegossener Analyzer zur Verfügung).

von JoeSeil (Gast)


Lesenswert?

@ King

Das glaube ich auch, das mit dem Bock meine ich. Aber es ist mir sehr
mystisch, was der Treiber macht. Irgendwie scheint der die empfangenen
Daten zu Filtern und für ihn uninteressante Dinge wegzuwerfen.
Übrigens funktioniert Readfile zwar nicht, aber Hid_GetFeature
funtkioniert. Dabei wird ein Get_Report Control Request ausgeführt.
Aber wieso geht das nicht mit ReadFile???
Vielen Dank für deine Antworten.

Beste Grüße
Joerg

von René K. (king)


Lesenswert?

Da wird definitiv nichts gefiltert. Der Host fragt Deinen Controller im
angegebenen Intervall ab und speichert den kompletten Report in einem
Ringbuffer. Wieviele Reports in diesem Buffer gespeichert werden, kannst
Du mit HidD_SetNumInputBuffers einstellen. ReadFile holt sich dann die
Daten aus diesem Buffer, sofern vorhanden.

Wenn das bei Dir nicht funktionieren will, kann es z.B. daran liegen,
daß Du die Requests lediglich NACKst. Oder vielleicht sendest Du Daten
in einer Länge, die sich nicht mit dem Descriptor deckt. Auch wenn ich
mich wiederhole, aber schau Dir das mit einem Protokoll Analyzer an,
z.B.:
http://sourceforge.net/projects/usbsnoop/

Ob der gut oder schlecht ist, kann ich, wie gesagt, nicht beurteilen.
Ich verwende ihn selber nicht. Aber ganz sicher ist das besser als gar
nichts.

von Maik Geßner (Gast)


Lesenswert?

@Weinga-Unity - snaky.1gmx.at

Kannst Du mir ein Angebot für dein "TUSB3210 Testaufbau" zu kommen
lassen???

von tunzer (Gast)


Lesenswert?

bei mir ist es genau umgekehrt:
ReadFile klappt super, das was ich mit den µC an einen Endpunkt (bei
mir EP1) lade, wird vom PC angefordert und visualisiert.
aber WriteFile klappt nicht. meine host-anwendung fängt dann an
"abzuschmieren". dann klappt nicht mal readFile mehr.
und obwohl ich GetLastError() aufrufe, wird kein fehler angezeigt.

die host-anwendung ist mit vb geschrieben. bei ReadFile hab ich den
overlapped-modus aktiviert wegen dem multithreading. bei WriteFile
nicht, könnte es daran liegen?

von tunzer (Gast)


Lesenswert?

übrigens benutze ich als µC einen PSoC. ist super leicht handzuhaben.
und vorallem kann man in kurzer zeit eine usb-gerät/application
programmieren. ich bin begeistert

von René K. (king)


Lesenswert?

> die host-anwendung ist mit vb geschrieben. bei ReadFile hab ich den
> overlapped-modus aktiviert wegen dem multithreading. bei WriteFile
> nicht, könnte es daran liegen?

Das verstehe ich nicht. Overlapped wird bei CreateFile mit dem Flag
FILE_FLAG_OVERLAPPED aktiviert und nirgendwo anders. Einmal aktiviert
gilt das für WriteFile ebenso wie für ReadFile. Mir ist es ein
absolutes Rätsel, wie Du bei diesen Funktionen etwas aktivieren/
deaktivieren willst.

Beachten mußt Du aber, daß wenn Du mit FILE_FLAG_OVERLAPPED arbeitest,
der letzte Parameter nicht genullt werden darf:

"If hFile was opened with FILE_FLAG_OVERLAPPED, the lpOverlapped
parameter must not be NULL."

Quelle (Beschreibung des letzten Parameters):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/writefile.asp?frame=true

Außerdem verstehe ich nicht, wie und wo Du GetLastError aufrufst, wenn
doch während des WriteFile-Aufrufes die Anwendung abschmiert.

von René K. (king)


Lesenswert?

> übrigens benutze ich als µC einen PSoC. ist super leicht
> handzuhaben. und vorallem kann man in kurzer zeit eine usb-
> gerät/application programmieren. ich bin begeistert

Ich verwende nicht den PSoC. Ich habe einen Controller, für den es vom
Hersteller bereits eine fix und fertige HID Firmware gibt. Da mußt Du
gar nichts mehr programmieren. Ich bin begeistert.

von tunzer (Gast)


Lesenswert?

sorry, dass ich mich unverständlich ausgedrückt habe. das wenn ich mit
FILE_FLAG_OVERLAPPED arbeite den letzte Parameter nicht nullen darf,
weiß ich auch.

Das sind einer meiner aufrufe der api, vielleicht versteht man besser
was ich meine:

Public Function OpenForRead(FileName As String) As Long
  OpenForRead = CreateFile(FileName, GENERIC_READ,
FILE_SHARE_READWRITE, SA, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
End Function

Public Function OpenForWrite(FileName As String) As Long
  OpenForWrite = CreateFile(FileName, GENERIC_WRITE,
FILE_SHARE_READWRITE, SA, OPEN_EXISTING, 0, 0)
End Function

...... GetLastError rufe ich wie folgt auf:

Success = WriteFile(WriteHandle, Sample_Rate(0), 2, BytesWritten, 0)
If (Success = 0) Then
        Message.Text = "Error " & GetLastError() & " sending command
to device"
        Call CloseProcessMonitoringDevice
        Exit Sub
    Else
        'anweisungen....
End if

ich denke es liegt an meiner firmware, werde mir noch mal den hid
report descriptor anschauen.

von tunzer (Gast)


Lesenswert?

>Ich verwende nicht den PSoC. Ich habe einen Controller, für den es
>vom
>Hersteller bereits eine fix und fertige HID Firmware gibt. Da mußt
>Du
>gar nichts mehr programmieren. Ich bin begeistert.

dann verrate uns doch welchen controller du benutzt :)

von René K. (king)


Lesenswert?

Wer oder was ist Sample_Rate(0) und was steht da drin? Bist Du sicher,
daß das Gerät nur ein einziges Byte an Nutzdaten erwartet (das geht,
ist dann aber doch ziemlich ungewöhnlich)?

von René K. (king)


Lesenswert?

> dann verrate uns doch welchen controller du benutzt :)

SiLabs C8051F320, im Moment schaue ich mir auch den F345 an.
Ausführliche Samples gibt es aber inzwischen von so ziemlich jedem
Hersteller.

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
Noch kein Account? Hier anmelden.