LibUSB Win32 Geräte einrichten und eigenen Treiber programmieren

Geräte für LibUSB bekommen einen speziellen Treiber

Ziel ist es, für den USB-Dongle PX-1674-675 ein ausführbares Programm (pxhex.exe) zu entwickeln, womit dieses Gerät aus Perl heraus bzw. über die Kommandozeile (Batch) angesteuert werden kann. Die Binary für die Adressierung (Hauscode, Gerät, On, Off) wird komplett mit Perl aufgearbeitet und als Hex-Dump an pxhex.exe übergeben. Auf der Kommandozeile sieht das so aus:

D:\>pxhex
Unwise Arguments
Use p.E.: 1A 85 E0 80 20 0A 00 18

D:\>pxhex 1A 85 E0 80 20 0A 00 18

Damit sind Schaltprozesse für Elektrogeräte automatisierbar und das Erstellen Gerätespezifischer Batchdateien wird möglich:

Datei on.bat bzw. on.cmd
pxhex 1A 85 F0 70 20 0A 00 18

Datei off.cmd
pxhex 1A 85 E0 80 20 0A 00 18

Womit mit einem einfachen on oder off auf der Kommandozeile eine bestimmte Steckdose Ein- bzw. ausgeschaltet werden kann.

pxhex.exe nimmt die übergebenen Argumente und erzeugt die für den usb_bulk_transfer erforderliche Binary. Doch bevor der c-Code entwickelt werden kann, sind noch ein paar Vorbereitungen zu treffen.

InfWizard

Geräte auf dem Universal-Serial-Bus geben sich zu erkennen mit einer Vendor-ID und einer Produkt-ID. Der mit LibUSB-Win32 mitgelieferte Inf-Wizard erlaubt das Einrichten ausgewählter Geräte für den Speziellen Treiber der LibUSB.

Uns interessiert das Gerät mit der Vendor-ID 0xFFFF und Product-ID 0x1122, genau das ist die Kennung für den eingesetzten USB-Dongle.

Nach Beenden des Inf-Wizard wird dieses Gerät im Gerätemanager an einer anderen Stelle/Gerätegruppe zu finden sein und ist dafür über die LibUSB-Win32 ansprechbar.

LibUSB Test

Das Dienstprogramm zeigt Properties und ob das Gerät richtig installiert wurde. Wichtig ist z.B. der Parameter bEndpointAddress, diese Angabe wird in unserem c-Programm benötigt:

// Device endpoint(s)
#define EP_IN 0x81
#define EP_OUT 0x02

Wobei EP_IN von LibUSB-Win32 fest vorgegeben ist.

Devices

Ansicht der über LibUSB eingerichteten Geräte im Gerätemanager. Das mit dem Inf-Wizard installierte Gerät befindet sich nun in dieser Gruppe.

LibUSB Treiber

Dieser Screenshot zeigt wo sich die Treiberdateien befinden. Sie sind von der LibUSB-Win32 aus dahin händisch zu kopieren. Dabei wird die libusb0_x86.dll umbenannt zu libusb0.dll

Entwicklungsumgebung MinGW

MinGW Shell

Download MinGW und MSYS und installieren über mingw-get-setup.exe. Sämtliche, auch später nachinstallierbare Pakete vermittelt eine grafische Oberfläche ähnlich wie Yast. Die MSYS-Shell wird über msys.bat gestartet.

In dieser Shell wird auch der Compiler aufgerufen gcc pxhex.c -lusb.

Damit die Preprocessor-Anweisung #include <usb.h> nicht ins Leere greift, sind untenstehende Dateien aus dem LibUSB-Win32-Verzeichnis in die Verzeichnisstruktur der Entwicklungsumgebung zu kopieren:

ln -s d:/2inst/libusb-win32-bin-1.2.6.0/include/lusb0_usb.h /mingw/include/usb.h
ln -s d:/2inst/libusb-win32-bin-1.2.6.0/lib/gcc/libusb.a /mingw/lib/
ln -s d:/2inst/libusb-win32-bin-1.2.6.0/bin/x86/libusb0_x86.dll /mingw/bin/libusb0.dll

Mit dem Download der libusb-win32 sind ein paar c-Beispiele dabei. Im Prinzip muss nur der Quellcode von bulk.c angepasst werden. Die Binary (Payload) für den Bulk-Transfer wird aus den Hex-Zahlen der Argumentenliste erzeugt:

    sprintf(payload, "%c%c%c%c%c%c%c%c",
        (int)strtol(argv[1], NULL, 16),
        (int)strtol(argv[2], NULL, 16),
        (int)strtol(argv[3], NULL, 16),
        (int)strtol(argv[4], NULL, 16),
        (int)strtol(argv[5], NULL, 16),
        (int)strtol(argv[6], NULL, 16),
        (int)strtol(argv[7], NULL, 16),
        (int)strtol(argv[8], NULL, 16)
    );

Untenstehende Funktion sucht das Device nach Vendor-ID und Product-ID auf dem Bus:

usb_dev_handle *open_dev(void){
    struct usb_bus *bus;
    struct usb_device *dev;

    for (bus = usb_get_busses(); bus; bus = bus->next){
        for (dev = bus->devices; dev; dev = dev->next){
            if (dev->descriptor.idVendor == MY_VID
                    && dev->descriptor.idProduct == MY_PID){
                return usb_open(dev);
            }
        }
    }
    return NULL;
}

Die Funktion usb_claim_interface(dev, 0) ist unbedingt auszuführen, ebenso die Funktion usb_set_configuration(dev, MY_CONFIG); danach erfolgt der Bulk-Transfer:

    ret = usb_bulk_write(dev, EP_OUT, payload, 8, 5000);

    if (ret < 0){
        printf("Error writing:\n%s\n", usb_strerror());
    }
    else{
        printf("success: bulk write %d bytes\n", ret);
    }

Nun kann die Programmdatei pxhex.exe erzeugt werden.


Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. s​os­@rolf­rost.de.