Setting Up Multiple FTDI Devices

Background

I’m building a test jig for a device that needs RS-232 and RS-485 transceivers. Since this is a test jig I prefer to build it out of off the shelf components, preferably ones that can be delivered overnight. Inside the jig I have the two dongles and a Labjack U3 connected to a USB hub. The hub connects to a USB isolator and then to a bulkhead mounted connector for easy disconnect. The jig is controlled using a laptop running Ubuntu with a test suite written in python.

The issue I’m having is telling on serial dongle apart from the other as both the RS-232 and RS-485 have identical vendor IDs, model, and revision. The serial device (/dev/ttyUSB*) depends on the order in which the devices were enumerated. The devices can be told apart by:

  1. Measuring the device outputs
  2. Keeping the position in the USB hub constant for the 232 & 485 dongles
  3. Storing the serial numbers
  4. Powering up the devices sequentially

Tools

The common Unix tools to manage devices are:

  1. udevadm - udev management tool (Dynamic device management)
  2. lsusb - list USB devices
  3. lshw - list hardware
  4. usb-devices - print USB device details

Finding Your Device

In my situation I’ve got the two dongles both showing up as serial ports:

> ls /dev/ttyUSB*
/dev/ttyUSB0  /dev/ttyUSB1
> udevadm info --query=property /dev/ttyUSB1
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.1/3-1.1:1.0/ttyUSB1/tty/ttyUSB1
DEVNAME=/dev/ttyUSB1
MAJOR=188
MINOR=1
SUBSYSTEM=tty
USEC_INITIALIZED=199589964479
ID_BUS=usb
ID_VENDOR_ID=0403
ID_MODEL_ID=6001
ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
ID_PCI_INTERFACE_FROM_DATABASE=XHCI
ID_VENDOR_FROM_DATABASE=Future Technology Devices International, Ltd
ID_MODEL_FROM_DATABASE=FT232 Serial (UART) IC
ID_VENDOR=FTDI
ID_VENDOR_ENC=FTDI
ID_MODEL=FT232R_USB_UART
ID_MODEL_ENC=FT232R\x20USB\x20UART
ID_REVISION=0600
ID_SERIAL=FTDI_FT232R_USB_UART_AG0JP1WN
ID_SERIAL_SHORT=AG0JP1WN
ID_TYPE=generic
ID_USB_INTERFACES=:ffffff:
ID_USB_INTERFACE_NUM=00
ID_USB_DRIVER=ftdi_sio
ID_PATH=pci-0000:00:14.0-usb-0:1.1:1.0
ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_1_1_0
ID_MM_CANDIDATE=1
ID_FOR_SEAT=tty-pci-0000_00_14_0-usb-0_1_1_1_0
DEVLINKS=/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AG0JP1WN-if00-port0 /dev/serial/by-path/pci-0000:00:14.0-usb-0:1.1:1.0-port0
TAGS=:seat:uaccess:systemd:snap_cups_cupsd:snap_cups_ippeveprinter:

The output are key value pairs separated by ‘=’, using this output with python is trivial but lets use shell commands for now.

Serial Number

> udevadm info --query=property /dev/ttyUSB1 | grep ID_SERIAL= | sed s/ID_SERIAL=// 
FTDI_FT232R_USB_UART_AG0JP1WN

> udevadm info --query=property /dev/ttyUSB0 | grep ID_SERIAL= | sed s/ID_SERIAL=//
FTDI_FT232R_USB_UART_A50285BI

Port

> udevadm info --query=property /dev/ttyUSB1 | grep DEVPATH= | sed s/DEVPATH=//
/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.1/3-1.1:1.0/ttyUSB1/tty/ttyUSB1

> udevadm info --query=property /dev/ttyUSB0 | grep DEVPATH= | sed s/DEVPATH=//
/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.2/3-1.2:1.0/ttyUSB0/tty/ttyUSB0

The ports differ by the number of the port in the hub. Moving USB1 from the first port to the third gives:

> udevadm info --query=property /dev/ttyUSB1 | grep DEVPATH= | sed s/DEVPATH=//
/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1.3/3-1.3:1.0/ttyUSB1/tty/ttyUSB1

Using horrific sed to separate out the port number:

> udevadm info --query=property /dev/ttyUSB1 | grep DEVPATH= | sed s/DEVPATH=// | sed s/"\/"/\\n/g | sed '7!d' | sed s/"\."/\\n/ | sed '2!d'
3

> udevadm info --query=property /dev/ttyUSB0 | grep DEVPATH= | sed s/DEVPATH=// | sed s/"\/"/\\n/g | sed '7!d' | sed s/"\."/\\n/ | sed '2!d'
2

My preference is to use the port number of the hub for identification. This way assembly instructions can be used with no software changes. As long as the device are always hooked up the same way then no configuration needs to be done.