Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

How to detect individual USB-RS232 device tty number?

Sun Apr 26, 2020 9:46 pm

I am planning a conversion from Windows to Raspbian of a software control program.
It uses two serial ports to handle external equipment and I was planning to use a pair of USB-RS232 converters.
The two channels have completely different use and are connected to different boxes.

Now when looking at converting the Windows code from using ports like COM1, COM2 etc into using /dev/ttyS1, /dev/ttyS2 etc I noticed two problems:

1) The base name of serial ports is not consistent.
It looks like various Linux versions uses different names:
- On Raspbian Buster it looks like /dev/ttyN where N is a number.
- On Ubuntu 18.04 it looks like /dev/ttySN where N is a number

If I attach USB to Serial converter cables I get on both Raspbian and Ubuntu:
/dev/ttyUSB0, /dev/ttyUSB1 etc

2) The number for the USB device varies.
What happens is that the first detected converter cable gets /dev/USB0, the second /dev/USB1 etc
So depending on how they are detected by the operating system they get different port numbers.

QUESTION:
How is this normally handled in Linux software configuration-wise?
With the USB connections it is very important to know which is which, preferably by use the actual USB port it is connected to.
Is there some way to know which of ttyUSB0 and ttyUSB1 is connected to a specific USB port?
lsusb does not display any such information...
On Raspbian I get this:

Code: Select all

 $ lsusb
Bus 001 Device 007: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
Bus 001 Device 008: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC
And on Ubuntu 18 this:

Code: Select all

 lsusb
Bus 002 Device 005: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 002 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
So it is exactly the same and no info available to differentiate between the two.
If I unplug both and then plug the one that is ttyUSB1 it becomes ttyUSB0

My software is configured via ini file formatted configuration files on Windows and there the port numbers seem to stick.
Is there some serial number or the like that can be used to identify each USB cable uniquely?
Bo Berglund
Sweden

trejan
Posts: 2327
Joined: Tue Jul 02, 2019 2:28 pm

Re: How to detect individual USB-RS232 device tty number?

Sun Apr 26, 2020 10:16 pm

Bosse_B wrote:
Sun Apr 26, 2020 9:46 pm
Is there some way to know which of ttyUSB0 and ttyUSB1 is connected to a specific USB port?
lsusb does not display any such information...
"lsusb -t" will show you.

If you look in /dev/serial/by-path/ then you'll see the port number in the symlinks e.g. /dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.4:1.0-port0 -> /dev/ttyUSB0 the 4 you see is port 4 on the Pi.

It is better to use the serial number that FTDI chips have though.
Bosse_B wrote:
Sun Apr 26, 2020 9:46 pm
Is there some serial number or the like that can be used to identify each USB cable uniquely?
If you use the FT_PROG tool on the FTDI site then you can change the name + serial number. That will show up in /dev/serial/by-id/ as something like usb-FTDI_FT232R_USB_UART_12345678-if00-port0 -> /dev/ttyUSB0

No idea what happens if you use FT_PROG on a counterfeit FTDI chip though so beware.

User avatar
scruss
Posts: 3323
Joined: Sat Jun 09, 2012 12:25 pm
Location: Toronto, ON
Contact: Website

Re: How to detect individual USB-RS232 device tty number?

Sun Apr 26, 2020 10:37 pm

trejan wrote:
Sun Apr 26, 2020 10:16 pm
If you use the FT_PROG tool on the FTDI site then you can change the name + serial number. That will show up in /dev/serial/by-id/ as something like usb-FTDI_FT232R_USB_UART_12345678-if00-port0 -> /dev/ttyUSB0
They should be unique out of the box, so by-id/… should have unique paths
FT_PROG may brick counterfeit adapters.
‘Remember the Golden Rule of Selling: “Do not resort to violence.”’ — McGlashan.
Pronouns: he/him

Heater
Posts: 16303
Joined: Tue Jul 17, 2012 3:02 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 3:06 am

Bosse_B,

I'm wondering how you have handled this in Windows where USB serial adapters also change the COM: names depending on how things get plugged in.

As noted above you can identify USB-serial adapters by their vendor and product ids. With that you can create udev rules to give the same device name to the same adapter all the time. See for example this article: "Persistent names for usb-serial devices" http://hintshop.ludvig.co.nz/show/persi ... l-devices/

That is great and all but what if you change the serial adapters?

Then you may want to identify a serial link, via whatever USB/serial adapter, by the actual USB port it is plugged into instead. That can also be done with udev rules. See the examples and discussion here: https://unix.stackexchange.com/question ... ot-working
Memory in C++ is a leaky abstraction .

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 5:16 am

OK,
first, lsusb -t does not do the trick:

Code: Select all

 $ lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 3: Dev 5, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 4: Dev 6, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
Nothing here that I can use...

But now I have also checked the /dev/serial/by-id/ path I did not know about...
Here is the result with two converters plugged into the Ubuntu machine:

Code: Select all

$ ll /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 apr 26 23:55 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 apr 27 06:57 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB1
As you can see there is an actual difference in each line, it is the device serial numbers:
FTFK085Y and FTFK0869 respectively.

When I unplug them and then plug in different sequence I get this:

Code: Select all

$ ll /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 apr 27 07:01 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 apr 27 07:01 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB0
And here are the two cases when the units are plugged into the RPi4 USB ports:

Code: Select all

$ ll /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 Apr 27 07:04 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB0
lrwxrwxrwx 1 root root 13 Apr 27 07:04 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB1
#Unplug and reinsert in different sequence:
$ ll /dev/serial/by-id/
lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB0
So if I can read this S/N in my code then I could presumably identify the adapter that belongs to a specific connection....
It would be really good to be able to open the port based on the serial number instead of the ttyUSBx name.
Bo Berglund
Sweden

Heater
Posts: 16303
Joined: Tue Jul 17, 2012 3:02 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 6:39 am

Bosse_B wrote:
Mon Apr 27, 2020 5:16 am
So if I can read this S/N in my code then I could presumably identify the adapter that belongs to a specific connection....
It would be really good to be able to open the port based on the serial number instead of the ttyUSBx name.
The proper way to do this is to use udev rules and let Linux sort it out for you.

Create a file in the directory "/etc/udev/rules.d" called "99-usb-serial.rules" and put a line in there like so:

Code: Select all

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A6008isP", SYMLINK+="arduino"
What this says is that when a device with the given vendor id, product id and serial number is plugged Linux will give it the device name specified by the SYMLINK. In this example "arduino". You can use any name descriptive of the device on the end of your serial cable.

Now in your code you don't need to worry about any ids and such. Just open your device by the name you gave it as "/dev/mydevice".

Do have a read of the links I posted above for more info.
Memory in C++ is a leaky abstraction .

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 7:05 am

Heater wrote:
Mon Apr 27, 2020 6:39 am
Bosse_B wrote:
Mon Apr 27, 2020 5:16 am
So if I can read this S/N in my code then I could presumably identify the adapter that belongs to a specific connection....
It would be really good to be able to open the port based on the serial number instead of the ttyUSBx name.
The proper way to do this is to use udev rules and let Linux sort it out for you.

Create a file in the directory "/etc/udev/rules.d" called "99-usb-serial.rules" and put a line in there like so:

Code: Select all

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A6008isP", SYMLINK+="arduino"
What this says is that when a device with the given vendor id, product id and serial number is plugged Linux will give it the device name specified by the SYMLINK. In this example "arduino". You can use any name descriptive of the device on the end of your serial cable.

Now in your code you don't need to worry about any ids and such. Just open your device by the name you gave it as "/dev/mydevice".

Do have a read of the links I posted above for more info.
Thank you very much for the links! :)

While you were writing the reply above I have been testing the suggestions in your linked documents and they work just fine!
So I have now added the procedure to the README of the software we use to control the system so it won't be forgotten (it is stored in Subversion).

The only drawback I can see is that if a converter is replaced for some reason it will be a need for editing the udev file and insert the S/N of the replacement device so it will be recognized on plug-in.
But anyway it is a very good start!

PS:
We have built a PC board to handle digital outputs from the Windows system via a serial link and this board uses an FTDI chip so I expect it will have much the same fingerprint when inserted and can be set to use the same naming convention on Linux via the udev file.
I will have to ask the H/W guy to pick one up and test it on an RPi box.
DS
Bo Berglund
Sweden

Heater
Posts: 16303
Joined: Tue Jul 17, 2012 3:02 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 8:32 am

Great.

The only other option I can see is a udev rule that matches by the path of the USB socket, As shown in on of my links above. For example:

Code: Select all

SUBSYSTEM=="tty",ENV{ID_PATH}=="pci-0000:00:14.0-usb-0:10.1:1.0",SYMLINK+="ttyUSB001"
Then the port is nailed down by it's physical position on the Pi. Like proper serial ports were back in the pre plug'n'pray days.

But that has it's downsides as well of course.
Memory in C++ is a leaky abstraction .

User avatar
jojopi
Posts: 3289
Joined: Tue Oct 11, 2011 8:38 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 9:32 am

Bosse_B wrote:
Mon Apr 27, 2020 5:16 am

Code: Select all

lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB0
So if I can read this S/N in my code then I could presumably identify the adapter that belongs to a specific connection....
It would be really good to be able to open the port based on the serial number instead of the ttyUSBx name.
You do not need to manually parse the symlinks; you just open them. Ubuntu and Raspbian (like most other distros) are already giving your devices the same consistent /dev/serial/by-id/usb-FTDI names, based on serial number. You open the devices by those names, without caring which ttyUSBN they are pointing to.

Writing your own udev rules to do the same thing, but in a way that is not consistent with every other Linux box, is silly.

If you find the systematic names unwieldy for some reason, you can create additional symlinks somewhere outside of /dev.

Code: Select all

ln -s /dev/serial/by-id/usb-FTDI_US232R_FTFK0869-if00-port0 ~/ttyFTDI9

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 10:00 am

Thanks again!
I think the last suggestion, which I have now tested makes best sense at least for this project.
I put this into the file /etc/udev/rules.d/99-usb-serial.rules:

Code: Select all

SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0",SYMLINK+="ttyUSB001"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.2:1.0",SYMLINK+="ttyUSB002"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.3:1.0",SYMLINK+="ttyUSB003"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.4:1.0",SYMLINK+="ttyUSB004"
Now when I plug the USB-RS232 devices into the USB slots the result is like this when I have plugged the two top connectors of the 4.

Code: Select all

$ ll /dev | grep USB00
lrwxrwxrwx 1 root root           7 Apr 27 11:33 ttyUSB001 -> ttyUSB1
lrwxrwxrwx 1 root root           7 Apr 27 11:33 ttyUSB003 -> ttyUSB0
So with this solution I do not need to extract the serial number of the individual converters, the device name reflects the hardware location of the USB connector. This means that we can preconfigure the RPi4 units and define installation to use specific hardware USB ports for the connections!
This is perfect for this application.

I have also checked one such unit (RPi3, though) sitting across the world and it uses a different USB-RS232 device than I have here, a device from Brainboxes Ltd.

And it has a slightly different ID_PATH but also works fine with this:

Code: Select all

SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-3f980000.usb-usb-0:1.1:1.0",SYMLINK+="ttyUSB001"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-3f980000.usb-usb-0:1.2:1.0",SYMLINK+="ttyUSB002"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-3f980000.usb-usb-0:1.3:1.0",SYMLINK+="ttyUSB003"
SUBSYSTEM=="tty",ENV{ID_PATH}=="platform-3f980000.usb-usb-0:1.4:1.0",SYMLINK+="ttyUSB004"
As can be seen here:

Code: Select all

 $ ls -la /dev/ | grep ttyUSB00
lrwxrwxrwx  1 root root           7 Apr 27 04:48 ttyUSB003 -> ttyUSB0
So I see that it is connected to USB port 3 on this RPi3...
Bo Berglund
Sweden

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 10:06 am

jojopi wrote:
Mon Apr 27, 2020 9:32 am
Bosse_B wrote:
Mon Apr 27, 2020 5:16 am

Code: Select all

lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK085Y-if00-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 Apr 27 07:07 usb-FTDI_US232R_FTFK0869-if00-port0 -> ../../ttyUSB0
So if I can read this S/N in my code then I could presumably identify the adapter that belongs to a specific connection....
It would be really good to be able to open the port based on the serial number instead of the ttyUSBx name.
You do not need to manually parse the symlinks; you just open them. Ubuntu and Raspbian (like most other distros) are already giving your devices the same consistent /dev/serial/by-id/usb-FTDI names, based on serial number. You open the devices by those names, without caring which ttyUSBN they are pointing to.

Writing your own udev rules to do the same thing, but in a way that is not consistent with every other Linux box, is silly.

If you find the systematic names unwieldy for some reason, you can create additional symlinks somewhere outside of /dev.

Code: Select all

ln -s /dev/serial/by-id/usb-FTDI_US232R_FTFK0869-if00-port0 ~/ttyFTDI9
I do not see that Raspbian "out of the box" creates a device other than the ttyUSBx where x designates the order of detection of the USB device.
That is my problem really.
But given the second alternative I can now create a usable device which is identified by the positional number among the 4 USB connectors on the RPi and this is the ultimate solution for building (and replicating) a system using serial comm. No need to look for serial numbers anymore, just plug into connector 4 and use ttyUSB004...
Bo Berglund
Sweden

User avatar
jojopi
Posts: 3289
Joined: Tue Oct 11, 2011 8:38 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 10:50 am

Bosse_B wrote:
Mon Apr 27, 2020 10:06 am
I do not see that Raspbian "out of the box" creates a device other than the ttyUSBx where x designates the order of detection of the USB device.
The underlying devices are always called ttyUSBN, but those symlinks you showed are perfectly valid ways to open the device, and the symlinks automatically point to the correct device number.

If you prefer to refer to devices by port number instead of serial number, you should find there are already /dev/serial/by-path/ entries that do that as well.

Your rules are doing exactly the same thing as the standard rules. Not changing the device names, but adding symlinks, just with less portable names.

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 12:09 pm

jojopi wrote:
Mon Apr 27, 2020 10:50 am
Bosse_B wrote:
Mon Apr 27, 2020 10:06 am
I do not see that Raspbian "out of the box" creates a device other than the ttyUSBx where x designates the order of detection of the USB device.
The underlying devices are always called ttyUSBN, but those symlinks you showed are perfectly valid ways to open the device, and the symlinks automatically point to the correct device number.

If you prefer to refer to devices by port number instead of serial number, you should find there are already /dev/serial/by-path/ entries that do that as well.

Your rules are doing exactly the same thing as the standard rules. Not changing the device names, but adding symlinks, just with less portable names.
OK, I see this when I look at it:

Code: Select all

$ ll /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 Apr 27 11:33 platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0-port0 -> ../../ttyUSB1
lrwxrwxrwx 1 root root 13 Apr 27 11:33 platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.3:1.0-port0 -> ../../ttyUSB0

$ ll /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 Apr 27 11:33 /dev/ttyUSB0
lrwxrwxrwx 1 root root         7 Apr 27 11:33 /dev/ttyUSB001 -> ttyUSB1
lrwxrwxrwx 1 root root         7 Apr 27 11:33 /dev/ttyUSB003 -> ttyUSB0
crw-rw---- 1 root dialout 188, 1 Apr 27 11:33 /dev/ttyUSB1

It seems easier to put this into a conf file:

Code: Select all

ComPort=/dev/ttyUSB001
IOCtrl=/dev/ttyUSB003
Rather than:

Code: Select all

ComPort=/dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0-port0
IOCtrl=/dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.3:1.0-port0
Bo Berglund
Sweden

trejan
Posts: 2327
Joined: Tue Jul 02, 2019 2:28 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 12:26 pm

Bosse_B wrote:
Mon Apr 27, 2020 5:16 am
OK,
first, lsusb -t does not do the trick:

Code: Select all

 $ lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 3: Dev 5, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
        |__ Port 4: Dev 6, If 0, Class=Vendor Specific Class, Driver=ftdi_sio, 12M
Nothing here that I can use...
You asked to see what ports the devices were plugged into. It was to help you visualise the port number in the /dev/serial/by-path symlinks.
Bosse_B wrote:
Mon Apr 27, 2020 7:05 am
The only drawback I can see is that if a converter is replaced for some reason it will be a need for editing the udev file and insert the S/N of the replacement device so it will be recognized on plug-in.
As mentioned above, you can reprogram the FTDI serial number + description using the FT_PROG tool. Set the serial numbers to something fixed like 1000 and 2000. You can then setup your udev rules to always look for those two specific serial numbers to distinguish between them. You will need to remember to reprogram the adapters first though.

Heater
Posts: 16303
Joined: Tue Jul 17, 2012 3:02 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 1:14 pm

jojopi wrote:
Mon Apr 27, 2020 9:32 am
Writing your own udev rules to do the same thing, but in a way that is not consistent with every other Linux box, is silly.
Hardly. I think having names for devices that are meaningful to humans is a very good idea. Many people name their ports that way. Being consistent with every other Linux box is irrelevant. I have a radar connected to my Pi. I'm pretty sure nobody else does. It's damn nice to have my code refer to "/dev/radar" rather than some obscure vendor/product id or PCI path.

Or is it silly to use variable names in programming? We could just use the memory addresses. Why have file names? We can get to our data on disk with block and offset.
Memory in C++ is a leaky abstraction .

Bosse_B
Posts: 1036
Joined: Thu Jan 30, 2014 9:53 am

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 1:31 pm

A little extreme, but shows the problem...

When designing a system that is supposed to be deployed by other people I prefer to
be able to write instructions along the line:
1) Attach the USB cable from the switchbox to the upper left USB connector
2) Attach the USB serial interface from the instrument to the upper right USB connector
Then in the conf file having:

Code: Select all

ComPort=/dev/ttyUSB001
IOCtrl=/dev/ttyUSB003
All this with a Raspberry Pi4 preconfigured as I showed above to create these device names when the items are connected makes very much sense and makes it easier to maintain.
I have checked that the numbering 1-2-3-4 starts on the top right USB next to the Ethernet connector and goes down then to the top left and down.

Again I want to thank @Heater for the contributions that got me this far!
Very useful forum this!
Last edited by Bosse_B on Mon Apr 27, 2020 1:35 pm, edited 1 time in total.
Bo Berglund
Sweden

Heater
Posts: 16303
Joined: Tue Jul 17, 2012 3:02 pm

Re: How to detect individual USB-RS232 device tty number?

Mon Apr 27, 2020 1:34 pm

Exactly.

Also, I find myself running my code on devices other than a Pi. So having that "/dev/radar" or whatever it is common across all platforms is very helpful.
Memory in C++ is a leaky abstraction .

Return to “General discussion”