1

I have an USB devices that use FTDI chip that I can identify in Linux:

user@user:~/src/libftdi/build$ lsusb
Bus 009 Device 008: ID 0403:faf0 Future Technology Devices International, Ltd 

or:

user@user:~$ lsusb -v -d 0403:faf0

Bus 009 Device 008: ID 0403:faf0 Future Technology Devices International, Ltd 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0403 Future Technology Devices International, Ltd
  idProduct          0xfaf0 
  bcdDevice            6.00
  iManufacturer           1 Thorlabs
  iProduct                2 APT DC Motor Controller
  iSerial                 3 83836244
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower                0mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              2 APT DC Motor Controller
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0001
  Self Powered

I have installed pylibftdi and figured how to list them

In [26]: dev.driver.list_devices()
Out[26]: 
[('Thorlabs', 'APT DC Motor Controller', '83836244'),
 ('Thorlabs', 'APT DC Motor Controller', '83838416'),
 ('Thorlabs', 'APT DC Motor Controller', '83837686'),
 ('Thorlabs', 'APT DC Motor Controller', '83836852'),
 ('Thorlabs', 'APT DC Motor Controller', '83837812'),
 ('Thorlabs', 'APT DC Motor Controller', '83825518'),
 ('Thorlabs', 'APT DC Motor Controller', '83838377'),
 ('Thorlabs', 'APT DC Motor Controller', '83838379'),
 ('Thorlabs', 'APT DC Motor Controller', '83836769'),
 ('Thorlabs', 'APT DC Motor Controller', '83837688'),
 ('Thorlabs', 'APT DC Motor Controller', '83836926'),
 ('Thorlabs', 'APT DC Motor Controller', '83837767'),
 ('Thorlabs', 'APT DC Motor Controller', '83836887'),
 ('Thorlabs', 'APT DC Motor Controller', '83836737'),
 ('Thorlabs', 'APT DC Motor Controller', '83838436'),
 ('Thorlabs', 'APT DC Motor Controller', '83837639'),
 ('Thorlabs', 'APT DC Motor Controller', '83836040'),
 ('Thorlabs', 'APT DC Motor Controller', '83837769'),
 ('Thorlabs', 'Brushed Motor Controller', '27251492'),
 ('Thorlabs', 'Brushed Motor Controller', '27251539')]


In [1]: from pylibftdi import USB_PID_LIST, USB_VID_LIST, Device
In [2]: USB_PID_LIST.append(0xFAF0)
In [3]: dev = Device()
In [4]: dev.driver.libftdi_version()
Out[4]: libftdi_version(major=0, minor=0, micro=0, version_str='< 1.0 - no ftdi_get_library_version()', snapshot_str='unknown')

The documentation for the pylibusb says that the attribute device_id can be used to specify the device I am trying to connect to:

 |  __init__(self, device_id=None, mode='b', encoding='latin1', interface_select=None, device_index=0, **kwargs)
 |      Device([device_id[, mode, [OPTIONS ...]]) -> Device instance
 |      
 |      represents a single FTDI device accessible via the libftdi driver.
 |      Supports a basic file-like interface (open/close/read/write, context
 |      manager support).
:param device_id: an optional serial number of the device to open.
 |          if omitted, this refers to the first device found, which is
 |          convenient if only one device is attached, but otherwise
 |          fairly useless.

Here is my simple code where I am creating two instances dev1 and dev2. For dev2 i do not specify the device_id (hence no specific serial number) and for dev1 I do. I can succesfully communicate with the dev2 but not dev1:

>>>from pylibftdi import USB_PID_LIST, USB_VID_LIST, Device
>>>from struct import pack, unpack

>>>USB_PID_LIST.append(0xFAF0)

>>>command = pack('BBBBBB',0x05,0x00,0x00,0x00,0x50,0x01)

>>>dev2 = Device();
>>>dev2.baudrate = 115200;
>>>dev2.writelines(command);
>>>dev2.readline()
 '\x06\x00T\x00\x81P\xc0z\xf2\x04TDC001\x00\x00\x10\x00\x03\x00\x02\x00TDC001 DC Servo Drive\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00104927Apr\x00\x01\x00\x02\x00\x00\x00\x01\x00'

>>>dev1 = Device(device_id = '83838416');
>>>dev1.baudrate = 115200;
>>>dev1.writelines(command);
>>>dev1.readline()
''

Since, I have dozens of these USB devices connected to one computer, it is essential for me to be able to create an instance and talk to a device with defined serial number.

I am not sure if it is a bug or I am doing something wrong.

Added later:

Somehow it is history dependent. If I run the same code after restarting python, I get an empty string as a response. I don't know what I am doing different now from before.

In [1]: from pylibftdi import USB_PID_LIST, USB_VID_LIST, Device

In [2]: from struct import pack, unpack

In [3]: USB_PID_LIST.append(0xFAF0)

In [4]: command = pack('BBBBBB',0x05,0x00,0x00,0x00,0x50,0x01)

In [5]: dev2 = Device();dev2.baudrate = 115200;dev2.writelines(command);dev2.readline();

In [6]: dev2.__dict__
Out[6]: 
{'_baudrate': 115200,
 '_opened': True,
 'ctx': <ctypes.c_char_Array_1024 at 0x7ff2008a1b00>,
 'decoder': <encodings.latin_1.IncrementalDecoder at 0x7ff2006906d0>,
 'device_id': None,
 'device_index': 0,
 'driver': <pylibftdi.driver.Driver at 0x7ff200690610>,
 'encoder': <encodings.latin_1.IncrementalEncoder at 0x7ff200681f90>,
 'encoding': 'latin1',
 'fdll': <CDLL 'libftdi.so.1', handle 5627c1668650 at 7ff2011d08d0>,
 'interface_select': None,
 'mode': 'b'}

In [8]: 
Valentyn
  • 659
  • 1
  • 7
  • 28

1 Answers1

3

Are you interested in uart (like) modes only? If so you might take a look at pyserial. Especially the serial.tools.list_ports.comports() function:

import serial
import serial.tools.list_ports

print([(x.device,x.hwid,x.description,x.location,x.serial_number) for x in serial.tools.list_ports.comports()])

This way you might be able to get the right description and open then the port via

ports = [x.device for x in serial.tools.list_ports.comports() if search_string in x.hwid]
serial.Serial(ports[0], 115200)
Christian B.
  • 816
  • 6
  • 11
  • I don't care if it is UART like modes or USB. I need to uniquely identify each device. I thought pylibftdi can help me to connect to a specific controller from the list. I can uniquely identify each device by it's serial number which is stored on the FTDI chip itself instead of the non-volatile memory of the motor controller. – Valentyn Jun 10 '19 at 19:19
  • 1
    then try the first code part to check if x.serial_number or one of the other give you the expected result. If this is the case you can use the coresponding field for the lookup in the second code part. – Christian B. Jun 10 '19 at 19:44
  • I only see 2 /dev/ttyS4 and /dev/ttyS0 devices instead of all 20. and these are problably different devices. In [36]: serial.tools.list_ports.comports()[0].__dict__ Out[36]: {'description': 'n/a', 'device': '/dev/ttyS4', 'device_path': '/sys/devices/pci0000:00/0000:00:16.3', 'hwid': 'n/a', 'interface': None, 'location': None, 'manufacturer': None, 'name': 'ttyS4', 'pid': None, 'product': None, 'serial_number': None, 'subsystem': 'pci', 'usb_device_path': None, 'usb_interface_path': None, 'vid': None} – Valentyn Jun 10 '19 at 19:56
  • 1
    Indeed. My FT2232H devices reports with a hwid of "USB VID:PID=0403:6010 SER=" etc but I think they are all setup to use the VCP driver. So chances are that the FT chips built in into your controllers are configurated to use the D2XXX instead and that pyserial cannot find them due to that.You could try to use ft_prog to check/change that on one device for testing. – Christian B. Jun 10 '19 at 20:08
  • @Christin B. if I use pyusb I can get full description including serial number but I cannot query anything. I have started from posting this question (https://stackoverflow.com/questions/56486431/pyusb-read-always-returns-the-same-value) – Valentyn Jun 10 '19 at 20:13
  • @Christin B. I was able to see the devices with pyserial. I think I might have attached a different driver during my trials and errors. I have found the FT_prod but it is for windows only. https://www.ftdichip.com/Support/Utilities.htm#FT_PROG – Valentyn Jun 10 '19 at 20:41
  • FT_PROG is for flashing the EEPROM. E.G. you can check and change there all settings ranging from the PID:VID to the GPIO driving strength. One setting is actually if the VCP or the D2XXX should be selected but I never noticed a difference yet tbh. For using pyserial one needs the VCP to be active. What did comports report now? – Christian B. Jun 10 '19 at 20:44
  • I have rebooted by linux server and I have all 20 + 2 usb devices in UART mode. And 20 motor controllers do have x.serial_number attribute. I swear I have tried this before. I couldn't get the serial number via pyserial. So frustrating. {'description': 'APT DC Motor Controller',... 'manufacturer': 'Thorlabs', 'name': 'ttyUSB16', 'pid': 64240, 'product': 'APT DC Motor Controller', 'serial_number': '83836852', 'subsystem': 'usb-serial',.... 'vid': 1027} – Valentyn Jun 10 '19 at 20:55
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/194720/discussion-between-christian-b-and-valentyn). – Christian B. Jun 10 '19 at 21:04