Linux USB HID Device?

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Linux USB HID Device?

Beitrag von MmVisual »

Hallo,

Wie kann ich unter Linux mein USB HID Device finden und eine
Kommunikation mit dem aufnehmen?

Unter Windows gibt es die Befehle der HID.DLL (HidD_GetHidGuid,
SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces usw.).

Aber wie geht das unter Linux?

Der Hintergrund:
Ich habe einen Mikrocontroller, der soll möglichst einfach an jedem PC
ohne lästige Treiberinstallation laufen, also programmiere ich dort das
USB als HID Device. Damit lässt sich das Gerät unter Windows mit Hilfe
dieser HID.dll finden. Jetzt möchte ich gerne das gleiche unter Linux
machen.

In Google finde ich alles, aber keine Lösung für mein Problem.

(LibUSB hat leider den Nachteil, dass man diese Treiber installieren
muss, funktioniert dafür auch mit Linux)

Vielen Dank für eure Unterstützung.
EleLa - Elektronik Lagerverwaltung - www.elela.de

creed steiger
Beiträge: 957
Registriert: Mo 11. Sep 2006, 22:56

Re: Linux USB HID Device?

Beitrag von creed steiger »

Normal regelt unter Linux das das HAL

http://www.freedesktop.org/wiki/Software/hal

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

Unter linux musst du für libusb keine treiber installieren
und unter Windows kann man das auch im rahmen des Setup machen
bin damit sehr zufrieden
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

@Christian

Ich habe schon gelesen, sie waren bisher sehr aktiv mit USB und Lazarus.

Also am besten libusb verwenden? Ich habe Units in "AVRISPTOOL" gefunden, die für Windows und Linux geschrieben wurden.
Wenn ich die Treiber in meine EXE als Ressource mit ein binde, dann ist die EXE auch nur 80KB größer.
Setup-Paket habe ich keine, Motto: Start & Use...
EleLa - Elektronik Lagerverwaltung - www.elela.de

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

Es geht auch anders, es ist ein aufruf der libusb.dll mit dem man treiber im system registrieren kann.
Nach dem Motto:
Treiberregistriereung
Stecken Sie bitte jetzt das gerät an den USb Port
Treiber wird installiert
Benutzen

Sollte gut machbar sein unter Linux kann man den teil einfach weglassen.
Sie können auch die hid.dll nehmen ich für meinen teil will aber nur eine Bibliothek.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

Ich denke ich habe keine andere Wahl als die Libusb zu verwenden.

Ich habe rausgefunden, dass unter Linux es Befehle wie "ioctl(fd, HIDIOCGDEVINFO, &device_info);" gibt. Ein paar Sourcen habe ich gefunden, aber nur für C.

Da ich in sachen Linux ein Newcommer bin (na ja, Maus bewegen ist das gleiche ;) und alles Systeminterne komplett anders ist, werde ich für den Anfang Libusb verwenden.
Vieleicht gibt es in ein bis zwei Jahren auch was für FPC, die Zeit hilft da viele Probleme zu lösen...
(Natürlich keine Komplett-Lösung, aber Units die vieles schon bereit stellen und Beispiele)
EleLa - Elektronik Lagerverwaltung - www.elela.de

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

Wo ist denn jetzt das problem mit libusb ?
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

Noch gibts keines, nächste Woche hab ich Urlaub, da programmiere ich was.
Bisher meldet sich der Controller nur am Betriebssystem an, jetzt muss daa auch Daten über Endpoints empfangen und senden noch rein.
Ich schreibe wieder bei weiteren Ergenissen.
EleLa - Elektronik Lagerverwaltung - www.elela.de

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

Hallo,

Ich habe ein kleines-Test-Programm in Lazarus erstellt. Irgendwie klappt es nicht so richtig, also ich möchte in den EP1 was schreiben, aber im Controller kommt nichts an.

Code: Alles auswählen

procedure TfMain.FormCreate(Sender: TObject);
begin
  usb_init();
  Enumerate;
end;


Code: Alles auswählen

procedure TfMain.Enumerate;
var
  busses : PUSBBus;
  usb_bus: PUSBBus;
  dev :    PUSBDevice;
begin
   usb_init();
   usb_find_busses();
   usb_find_devices();
 
   busses := usb_get_busses();
   usb_bus := busses;
   while Assigned(usb_bus) do
   begin
      dev := usb_bus^.devices;
      while Assigned(dev) do
      begin
         if  (dev^.descriptor.idVendor = $8B15) and (dev^.descriptor.idProduct = $9CC6) then
            lstDspy.Items.AddObject('US "' + dev^.filename + '" ' + IntToStr(dev^.devnum),TObject(dev));
         dev := dev^.next;
      end;
      usb_bus := usb_bus^.next
   end;
   If lstDspy.Items.Count > 0 Then
      lstDspy.ItemIndex := 0;
end;


Code: Alles auswählen

procedure TfMain.btnSendClick(Sender: TObject);
var
  res, iEP: LongInt;
  Device : PUSBDevice;
  DeviceHandle: PUSBDevHandle;
  txt: PChar;
begin
   If (lstDspy.ItemIndex < 0) Then
       Exit;
   Device := Pointer(lstDspy.Items.Objects[lstDspy.ItemIndex]);
   DeviceHandle := usb_open(Device{$IFDEF WINDOWS}^{$ENDIF});
   If Assigned(DeviceHandle) Then
   Begin
 
      If usb_set_configuration(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, 1) < 0 Then
      Begin
         lbMsg.Caption := 'Err usb_set_configuration';
         usb_close(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF});
         Exit;
      End;
 
      If usb_claim_interface(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, 0) < 0 Then
      Begin
         lbMsg.Caption := 'Err usb_claim_interface';
         usb_close(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF});
         Exit;
      End;
      //usb_set_altinterface(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, 0);
 
      txt := PChar('HalloWelt0HalloWelt0HalloWelt0uu');
      res := usb_bulk_write(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, 1, txt, 32, 1);
 
      usb_release_interface(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF},0);
 
      usb_close(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF});
      lbMsg.Caption := 'EP: ' + IntToStr(rgEP.ItemIndex + iEP) + ' Result: ' + IntToStr(res);
   End Else lbMsg.Caption := 'Err DeviceHandle';
end;


In meinem Controller erscheinen nur Messages für den EP0, aber nicht für den EP1.
Ich bin mir auch nicht ganz sicher ob ich den Code für meinem Mikrocontroller richtig gemacht habe.
Kann hier bitte jemand drauf schauen ob ich nichts vergessen habe?

Vielen Dank für eure Hilfe.
EleLa - Elektronik Lagerverwaltung - www.elela.de

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

Schau dir doch mal die fehler an die libusb evntl zurückgibt. Res setzt du, aber nachschaun was da drin steht tust nicht.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

Ich habs hin bekommen! Als ich Ihnen den Fehler beschrieben habe, hab ich den Print vom "testlibusb-win.exe" angehängt, dann ist mir der Fehler aufgefallen. (Fehler -5 / -116 kam von "usb_bulk_write") So gehts:

Code: Alles auswählen

DLL version:   0.1.12.1
Driver version:   0.1.12.1
 
bus/device  idVendor/idProduct
bus-0/\\.\libusb0-0001--0x8b15-0x9cc6     8B15/9CC6
  wTotalLength:         74
  bNumInterfaces:       1
  bConfigurationValue:  1
  iConfiguration:       0
  bmAttributes:         80h
  MaxPower:             125
    bInterfaceNumber:   0
    bAlternateSetting:  0
    bNumEndpoints:      8
    bInterfaceClass:    0
    bInterfaceSubClass: 0
    bInterfaceProtocol: 0
    iInterface:         0
      bEndpointAddress: 01h
      bmAttributes:     02h
      wMaxPacketSize:   64
      bInterval:        1
      bRefresh:         0
      bSynchAddress:    0
      bEndpointAddress: 81h
      bmAttributes:     02h
      wMaxPacketSize:   64
      bInterval:        1
      bRefresh:         0
      bSynchAddress:    0
      ... (nochmal 3* IN/OUT EP's)


PS: Oftmals hilft einfach eine Nacht Schlafen und drüber schreiben... Vielen Dank!
EleLa - Elektronik Lagerverwaltung - www.elela.de

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

Sie brauchen mich nicht zu siezen :) ist eher unüblich hier.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

OK.
Ich bin gerade dabei eine EXE zu machen, mit der ich Bulk / Interrupt usw. übertragen und testen kann.
Darin habe ich auch eine Baum-Ansicht mit der gesammten Interface/EP Konfiguration. Irgendwie zeigt mir das ganze nicht das an, wie in der C-Demo Applikation.
Kannst Du da mal einen Blick drauf werfen?

Das Problem:
Zeile 61, wTotalLength zeigt 0, in "testlibusb.exe" 74
Zeile 67, in "i2" wird ebenfalls -1 rein geschrieben, dadurch werden die anderen Schleifen erst gar nicht durchlaufen.
Ein Fehler erscheint nicht.

Code: Alles auswählen

procedure TfMain.lstDspyClick(Sender: TObject);
Var it, it2, it2i, it2e: TTreeNode;
    ret, i, k, m, n, i2: LongInt;
    s: String;
    Device : PUSBDevice;
    DeviceHandle: PUSBDevHandle;
    descriptor: PUSBDeviceDescriptor;
    config: PUSBConfigDescriptor;
    intf: PUSBInterface;
    altsetting: PUSBInterfaceDescriptor;
    endpoint: PUSBEndpointDescriptor;
    str: Array [0..255] of Char;
begin
   tvDev.Items.Clear;
     If (lstDspy.ItemIndex < 0) Then
       Exit;
     Device := Pointer(lstDspy.Items.Objects[lstDspy.ItemIndex]);
   descriptor := @Device{$IFDEF WINDOWS}^{$ENDIF}.descriptor;
   If Not Assigned(descriptor) Then
      Exit;
 
     DeviceHandle := usb_open(Device{$IFDEF WINDOWS}^{$ENDIF});
     If Assigned(DeviceHandle) Then
   Begin
      If (descriptor{$IFDEF WINDOWS}^{$ENDIF}.iManufacturer) <> 0 Then
      Begin
         ret := usb_get_string_simple(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, descriptor{$IFDEF WINDOWS}^{$ENDIF}.iManufacturer, str, Length(str));
         If (ret > 0) Then
            s := str + ' - '
         Else s := '0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idVendor, 4) + ' - ';
      End Else s := '0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idVendor, 4) + ' - ';
 
      If (descriptor{$IFDEF WINDOWS}^{$ENDIF}.iProduct) <> 0 Then
      Begin
         ret := usb_get_string_simple(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, descriptor{$IFDEF WINDOWS}^{$ENDIF}.iProduct, str, Length(str));
         If (ret > 0) And (Trim(str) <> '') Then
            s := s + str
         Else s := s + '0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idProduct, 4);
      End Else s := s + '0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idProduct, 4);
 
      it := tvDev.Items.AddFirst(Nil, s);
 
      If (descriptor{$IFDEF WINDOWS}^{$ENDIF}.iSerialNumber) <> 0 Then
      Begin
         ret := usb_get_string_simple(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF}, descriptor{$IFDEF WINDOWS}^{$ENDIF}.iSerialNumber, str, Length(str));
         s := 'Seriennummer: ' + str;
         tvDev.Items.AddChild(it, s);
      End;
      usb_close(DeviceHandle{$IFDEF WINDOWS}^{$ENDIF});
   End Else Begin
      s := '0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idVendor, 4) + ' - 0x' + IntToHex(descriptor{$IFDEF WINDOWS}^{$ENDIF}.idProduct, 4);
      it := tvDev.Items.AddChild(it, s);
   End;
 
   config := @Device{$IFDEF WINDOWS}^{$ENDIF}.config;
   If Assigned(config) Then
   Begin
      For i := 0 To Device{$IFDEF WINDOWS}^{$ENDIF}.descriptor.bNumConfigurations - 1 Do
      Begin
         it2 := tvDev.Items.AddChild(it, 'Configuration: ' + IntToStr(i));
         tvDev.Items.AddChild(it2, 'wTotalLength: ' + IntToStr(config[i].wTotalLength));
         tvDev.Items.AddChild(it2, 'bNumInterfaces: ' + IntToStr(config[i].bNumInterfaces));
         tvDev.Items.AddChild(it2, 'bConfigurationValue: ' + IntToStr(config[i].bConfigurationValue));
         tvDev.Items.AddChild(it2, 'iConfiguration: ' + IntToStr(config[i].iConfiguration));
         tvDev.Items.AddChild(it2, 'bmAttributes: ' + IntToStr(config[i].bmAttributes));
         tvDev.Items.AddChild(it2, 'MaxPower: ' + IntToStr(config[i].MaxPower));
         i2 := config[i].bNumInterfaces - 1;
         For k := 0 To i2 Do
         Begin
            intf := @config[i].intf;
            altsetting := @intf[k].altsetting;
            If Assigned(Intf) And Assigned(altsetting) Then
            Begin
               it2i := tvDev.Items.AddChild(it2, 'Interfaces ' + IntToStr(k));
               For m := 0 To intf[k].num_altsetting - 1 Do
               Begin
                  tvDev.Items.AddChild(it2i, 'bInterfaceNumber: ' + IntToStr(altsetting[m].bInterfaceNumber));
                  tvDev.Items.AddChild(it2i, 'bAlternateSetting: ' + IntToStr(altsetting[m].bAlternateSetting));
                  tvDev.Items.AddChild(it2i, 'bNumEndpoints: ' + IntToStr(altsetting[m].bNumEndpoints));
                  tvDev.Items.AddChild(it2i, 'bInterfaceClass: ' + IntToStr(altsetting[m].bInterfaceClass));
                  tvDev.Items.AddChild(it2i, 'bInterfaceSubClass: ' + IntToStr(altsetting[m].bInterfaceSubClass));
                  tvDev.Items.AddChild(it2i, 'bInterfaceProtocol: ' + IntToStr(altsetting[m].bInterfaceProtocol));
                  tvDev.Items.AddChild(it2i, 'iInterface: ' + IntToStr(altsetting[m].iInterface));
                  endpoint := @altsetting[m].endpoint;
                  If Assigned(endpoint) Then
                  Begin
                     For n := 0 To altsetting[m].bNumEndpoints Do
                     Begin
                        it2e := tvDev.Items.AddChild(it2i, 'Endpoint ' + IntToStr(n));
                        tvDev.Items.AddChild(it2e, 'bEndpointAddress: ' + IntToStr(endpoint[n].bEndpointAddress));
                        tvDev.Items.AddChild(it2e, 'bmAttributes: ' + IntToStr(endpoint[n].bmAttributes));
                        tvDev.Items.AddChild(it2e, 'wMaxPacketSize: ' + IntToStr(endpoint[n].wMaxPacketSize));
                        tvDev.Items.AddChild(it2e, 'bInterval: ' + IntToStr(endpoint[n].bInterval));
                        tvDev.Items.AddChild(it2e, 'bRefresh: ' + IntToStr(endpoint[n].bRefresh));
                        tvDev.Items.AddChild(it2e, 'bSynchAddress: ' + IntToStr(endpoint[n].bSynchAddress));
                     End;
                  End;
               End;
            End;
         End;
      End;
   End;
 
   tvDev.Items[0].Expand(True);
end;


Die Enumerate-Funktion:

Code: Alles auswählen

procedure TfMain.Enumerate;
var
  usb_bus: PUSBBus;
  dev :    PUSBDevice;
begin
   usb_find_busses();
   usb_find_devices();
   usb_bus := usb_get_busses();
   lstDspy.Items.Clear;
   tvDev.Items.Clear;
   while Assigned(usb_bus) do
   begin
      dev := usb_bus{$IFDEF WINDOWS}^{$ENDIF}.devices;
      while Assigned(dev) do
      begin
          lstDspy.Items.AddObject(dev{$IFDEF WINDOWS}^{$ENDIF}.filename + '   ' + IntToStr(dev{$IFDEF WINDOWS}^{$ENDIF}.devnum),TObject(dev));
         dev := dev{$IFDEF WINDOWS}^{$ENDIF}.next;
      end;
      usb_bus := usb_bus{$IFDEF WINDOWS}^{$ENDIF}.next
   end;
   If lstDspy.Items.Count > 0 Then
      lstDspy.ItemIndex := 0;
end;
EleLa - Elektronik Lagerverwaltung - www.elela.de

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Linux USB HID Device?

Beitrag von Christian »

kannst du mal das testprojekt anhängen?
würd das gern mal probiern.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

MmVisual
Beiträge: 1445
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 3.0 FPC 3.2)
CPU-Target: 32/64Bit

Re: Linux USB HID Device?

Beitrag von MmVisual »

Anbei das Projekt.
Klick in die Liste der USB Geräte baut den Baum auf. Für Windows (Linux noch nie geprüft).

Update: Ich habe die Datei eneut hochgeladen, nun sind in der Datei "libusb_win32.pas" die Typbezeichnungen richtig und andere kleine Verbesserungen. Das Problem konnte ich noch nicht lösen :(
Ich habe auch experimentiert mit Packed und nicht, C-Sourcen studiert, aber ich komme einfach nicht dahinter.

PS: Das Abholen von USB EP Datenpakete geht auch nicht (IN), nur das verschicken (OUT).
Dateianhänge
V4_Test_USB.zip
(11.52 KiB) 86-mal heruntergeladen
EleLa - Elektronik Lagerverwaltung - www.elela.de

Antworten