Forum: PC-Programmierung Navigation im USB Tree


von B. W. (yesitsme)


Lesenswert?

Ich habe ein Problem:

Ich habe einen Aufbau aus meheren USB Geräten. Diese sind an einem USB 
Hub angeschlossen.

An Port 1 wird ein /dev/ttyACM0 erkannt. Da es eine Seriennummer hat, 
kann ich mit pySerial über alle erkannten Ports enumerieren und die 
Seriennummer vergleichen.
-> Kein Problem hier.

An Port 2 habe ich ein /dev/ttyUSB0. Leider ohne Seriennummer.

Da jenachdem was ich noch angeschlossen habe, sich die Namen ändern hier 
meine Frage:

Wie komme ich am besten unter Linux und Python von /dev/ACM0 (den ich 
sicher finden kann) auf /dev/ttyUSB0 (der ein Port weiter eingesteckt 
ist)?

von Norbert (der_norbert)


Lesenswert?

B. W. schrieb:
> An Port 2 habe ich ein /dev/ttyUSB0. Leider ohne Seriennummer.
>
> Da jenachdem was ich noch angeschlossen habe, sich die Namen ändern hier
> meine Frage:

In ›/etc/udev/rules.d‹ eine Regel einführen, welche auf Vid:Pid triggert 
und einen eigens erstellten und benannten Link in /dev hinzu fügt.

Habe mir vor Äonen so etwas erstellt:
1
# stm32 discovery board with onboard st/linkv2
2
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", \
3
    MODE:="0666", \
4
    SYMLINK+="stlinkv2_%n"

von B. W. (yesitsme)


Lesenswert?

An sich eine gute Idee, aber leider haben die CH340 irgendwie alle die 
selbe VID:PID. Da bleibt dann noch die unterschiedliche Enumerierung bei 
Boot und Hotplug...

von Norbert (der_norbert)


Lesenswert?

B. W. schrieb:
> aber leider haben die CH340 irgendwie alle die
> selbe VID:PID.

Ahhh, diese Information gab's gerade noch nicht.

Gleiche VID, gleiche PID, keine SERIAL.
Device ──▶ /dev/null

von Εrnst B. (ernst)


Lesenswert?

Und wenn du mehrere Devices hast, die sich nicht durch VID/PID oder 
Seriennummer unterscheiden, kannst du die udev-Rule auch nach 
Device-Pfad unterscheiden, als z.B. je nachdem in welchen Port vom 
USB-Hub die gesteckt sind:
1
... ENV{ID_PATH}=="pci-0000:01:00.0-usb-0:2.3:1.0",SYMLINK+="ttyUSB_HUB_PORT3"...

Im ENV{ID_PATH} - Match gehen Wildcards, Wenn es egal sein soll an 
welchem Mainboard-Port der Hub steckt, kannst du das entsprechend 
raus-'*'-en.

Und wenn dir eigene UDEV-Rules suspekt sind, schau mal in die 
unterordner von /dev/serial, die Default-UDEV-Regeln legen da schon 
einige Symlinks an, die dir reichen könnten.

von Norbert (der_norbert)


Lesenswert?

Εrnst B. schrieb:
> Und wenn du mehrere Devices hast, die sich nicht durch VID/PID
> oder
> Seriennummer unterscheiden, kannst du die udev-Rule auch nach
> Device-Pfad unterscheiden,

Stimmt. Aber dann fliegt er blind, da die Geräte nicht unterscheidbar 
sind und nun ausschließlich von der Steckposition abhängen. Da braucht 
man große Aufkleber und blinkende Pfeile an den Hubs.

von Gerd E. (robberknight)


Lesenswert?

Εrnst B. schrieb:
> Und wenn du mehrere Devices hast, die sich nicht durch VID/PID oder
> Seriennummer unterscheiden, kannst du die udev-Rule auch nach
> Device-Pfad unterscheiden, als z.B. je nachdem in welchen Port vom
> USB-Hub die gesteckt sind:

genau.

> ENV{ID_PATH}=="pci-0000:01:00.0-usb-0:2.3:1.0",SYMLINK+="ttyUSB_HUB_PORT 3"...

und um diesen ID_PATH herauszubekommen, kannst Du den udevadm-Befehl 
verwenden:
1
udevadm info /dev/ttyUSB0

: Bearbeitet durch User
von B. W. (yesitsme)


Lesenswert?

Gerd E. schrieb:
> udevadm info /dev/ttyUSB0


Hmm... mal schauen wie ich das parse...
1
P: /devices/pci0000:00/0000:00:08.1/0000:29:00.3/usb5/5-1/5-1.1/5-1.1.2/5-1.1.2:1.0/ttyUSB1/tty/ttyUSB1
2
P: /devices/pci0000:00/0000:00:08.1/0000:29:00.3/usb5/5-1/5-1.1/5-1.1.1/5-1.1.1:1.0/tty/ttyACM1

von Εrnst B. (ernst)


Lesenswert?

B. W. schrieb:
> Hmm... mal schauen wie ich das parse...

Schau nach der Zeile mit ID_PATH

# udevadm info /dev/ttyACM1 |grep ID_PATH=
E: ID_PATH=pci-0000:01:00.0-usb-0:2.3:1.0

das "E:" davor bedeutet, dass der Wert in der Rule mit ENV{} erreichbar 
ist.

von Rahul D. (rahul)


Lesenswert?

Norbert schrieb:
> Stimmt. Aber dann fliegt er blind, da die Geräte nicht unterscheidbar
> sind und nun ausschließlich von der Steckposition abhängen.

Ist doch in Ordnung, solange man sie nicht umsteckt.
Bei manchen Aufbauten ändert sich ja nichts. Und wenn man das alles in 
eine Kiste steckt und außen dann SubD-Steckverbinder für irgendwelche 
UART-basierte Geräte (wovon ich bei der Verwendung von CH340 ausgehe) 
hat, kann man die SubDs einfach entsprechend bezeichnen ("labeln").

von Frank K. (fchk)


Lesenswert?

Kann man nicht die CH340 durch FTDI's ersetzen? Das würde das ganze 
Problem nachhaltig und sauber lösen.

fchk

von B. W. (yesitsme)


Lesenswert?

Rahul D. schrieb:
> Ist doch in Ordnung, solange man sie nicht umsteckt.

Und genau darum will ich mir keine Sorgen machen.

Alles in eine Kiste stecken? Ja bitte.

Rahul D. schrieb:
> SubD-Steckverbinder

Ich hätte da eine Handvoll Fragen...
 * Mach ich da am besten meine eigene Belegung oder nehme ich einen 
Standard?
 * Wie finde ich das im System wieder?
 * ...

Frank K. schrieb:
> CH340 durch FTDI's ersetzen?

Ich würde jetzt nicht auf FTDI gehen da ich mit einem FT4232 schon 
Probleme hatte:
 * braucht ein EEPROM für die SN
 * schickt bei STOP des HW-Flows noch 2 Bytes über die Leitung

Würde da dann auf den CP2102 gehen.


Ist jetzt nicht schön, aber fängt an zu funktionieren:
1
import pyudev
2
from pprint import pprint
3
import types
4
5
def printDevice(device):
6
    print(device)
7
    #print(dir(device))
8
9
    for n in dir(device):
10
        if n.startswith("__"):
11
            continue
12
13
        v = getattr(device, n)
14
        if isinstance(v, types.GeneratorType):
15
            v = list(v)
16
17
        print(n, v)
18
    
19
    for k, v in device.items():
20
        print(f" * {k}: {v}")
21
22
def main(serial):
23
    context = pyudev.Context()
24
    device = list(context.list_devices(ID_SERIAL_SHORT=serial))[0]
25
    hub = device.parent
26
    
27
    #printDevice(device)
28
    
29
    for port in range(1,5):
30
        sysName = hub.sys_name + f".{port}"
31
        for c in hub.children:
32
            if c.sys_name == sysName:
33
                for sc in c.children:
34
                    #printDevice(sc)
35
                    dn = sc.get("DEVNAME")
36
                    if dn:
37
                        print(port, dn)
38
39
if __name__ == "__main__":
40
    import sys
41
    main(sys.argv[1])

von Rahul D. (rahul)


Lesenswert?

B. W. schrieb:
> Rahul D. schrieb:
>> Ist doch in Ordnung, solange man sie nicht umsteckt.
>
> Und genau darum will ich mir keine Sorgen machen.
>
> Alles in eine Kiste stecken? Ja bitte.
Es gibt doch zwei Möglichkeiten:
Die Belegung des Busses ändert sich nicht, und man kann die Bausteine 
anhand des USB-Tree ansprechen.
Oder: man verwendet Bausteine mit einer einzigartigen Seriennummer.

>
> Rahul D. schrieb:
>> SubD-Steckverbinder
>
> Ich hätte da eine Handvoll Fragen...
>  * Mach ich da am besten meine eigene Belegung oder nehme ich einen
> Standard?
>  * Wie finde ich das im System wieder?
>  * ...
RS232 hat eine Standardbelegung je nach Steckergröße (9 oder 25 polig) 
und nach Geräte (DCE oder DTE). Davon gehe ich bei der Verwendung eines 
CH340 aus. Wenn es keine Standard-Schittstelle ist, und man sie mit was 
anderem (u.U. für die Schaltung gefährlichem) vertauschen kann, wäre 
eine eigene Belegung oder ein anderer Steckverbindertyp angebracht.

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.