eblot / pyftdi

FTDI device driver written in pure Python
Other
509 stars 211 forks source link

Open device by bus number and address #136

Closed RyanHope closed 5 years ago

RyanHope commented 5 years ago

I have a bunch of fake ftdi chips that all have the same manu/product/serial info, When I used pyftdi's methods of listing devices by vendor id I only list one of the adapters if I have multiple connected to the same machine. The only way to identify them is by their bus number and address. I couldn't think of a good way to create a new open method that takes bus number/address so instead I created a new open method that accepts a device directly as returned by usb.core.find. This seems to be working fine. I just extended the Ftdi class in my project but I could make a proper PR if interested.

eblot commented 5 years ago

You can add a PR. I'm not sure it can be included into the project, but it could help other users with EEPROM-less boards. Thanks.

RyanHope commented 5 years ago

I'm not sure that this issue is specific for fake chips though. Your code should still be able to list and select from multiple devices if multiple are present.

On Thu, Aug 1, 2019, 10:03 AM Emmanuel Blot notifications@github.com wrote:

You can add a PR. I'm not sure it can be included into the project, but it could help other users with EEPROM-less boards. Thanks.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/eblot/pyftdi/issues/136?email_source=notifications&email_token=AABCNTJTXSCII7QJQE6ANE3QCLUKLA5CNFSM4IHFE6I2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3KWMAI#issuecomment-517301761, or mute the thread https://github.com/notifications/unsubscribe-auth/AABCNTI5L6YHFYO6V2MOQHLQCLUKLANCNFSM4IHFE6IQ .

eblot commented 5 years ago

It is not related to fake chips but to the absence of EEPROM (or properly flashed EEPROM).

However, the code does work with several identical chips connected:

Example: url=ftdi:///?:

 Available interfaces:
  ftdi://ftdi:232:FTH19HLV/1    (TTL-232R-3V3-AJ)
  ftdi://ftdi:232:FTH1GMPE/1    (TTL-232R-3V3-AJ)
  ftdi://ftdi:232h:FTVOLDVA/1   (C232HD-DDHSP-0)

The trouble is to identify which device is actually connected, I'm not sure the bus/address can help as the USB bus may be re-enumerated and bus/address keep changing.

RyanHope commented 5 years ago

That's a bad example, the devices are not identical as they have different serial numbers.

On Thu, Aug 1, 2019, 10:27 AM Emmanuel Blot notifications@github.com wrote:

It is not related to fake chips but to the absence of EEPROM (or properly flashed EEPROM).

However, the code does work with several identical chips connected:

Example: url=ftdi:///?:

Available interfaces: ftdi://ftdi:232:FTH19HLV/1 (TTL-232R-3V3-AJ) ftdi://ftdi:232:FTH1GMPE/1 (TTL-232R-3V3-AJ) ftdi://ftdi:232h:FTVOLDVA/1 (C232HD-DDHSP-0)

  • first TTL-232R-3V3-AJ can be open with either url=ftdi://ftdi:232:FTH19HLV/1 (by serial number) or url=ftdi://ftdi:232:1/1 (by index)
  • second TTL-232R-3V3-AJ can be open with either url=ftdi://ftdi:232:FTH1GMPE/1 (by serial number) or url=ftdi://ftdi:232:2/1 (by index)

The trouble is to identify which device is actually connected, I'm not sure the bus/address can help as the USB bus may be re-enumerated and bus/address keep changing.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/eblot/pyftdi/issues/136?email_source=notifications&email_token=AABCNTMBQ4V2SWZWQO4QQ3TQCLXG5A5CNFSM4IHFE6I2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3KYZHQ#issuecomment-517311646, or mute the thread https://github.com/notifications/unsubscribe-auth/AABCNTJWYDRS42NJWQQE3GLQCLXG5ANCNFSM4IHFE6IQ .

eblot commented 5 years ago

Ok, I got it: I never tested a case with identical chips and no (or identical) serial number. It should definitely be fixed.

eblot commented 5 years ago

I will introduce bus and address explicit syntax, and use open_from_device:

Available interfaces:
  ftdi://ftdi:232h:FTH19HLV/1   (TTL-232R-3V3-AJ)
  ftdi://ftdi:232h:FTH1GMPE/1   (TTL-232R-3V3-AJ)
  ftdi://ftdi:232h:14:2c/1
  ftdi://ftdi:232h:14:2e/1

4 distinct FTDI devices in the above example, two with S/N, two other ones w/o.

eblot commented 5 years ago

See usb_bus_address branch (WIP)

zhenqlin commented 5 years ago

I encountered similar issue. I have FT2232H device with same serial number. when I use spi.configure('ftdi://::/1'), sometime connect to A channel sometime connect to B and spi.configure('ftdi://::/2') doesn't work. How to fix this?

eblot commented 5 years ago

@zhenqlin I'm not sure to understand your message:

Do you have two (or more) FTDI devices w/ no serial numbers?

I do not see how the host could use A or B channels randomly, as channel selection is not related to device selection. It can change which FTDI device it uses each time your Python application is run, but .../1 always means "channel A" and .../2 means "channel B"

Please give a try to the usb_bus_address branch and use the new bus:address specifiers to select a specific device, ''i.e.'': ftdi://::bus:address/1 and ftdi://::bus:address/2.

zhenqlin commented 5 years ago

Thanks for reply. Doesn't look like working. here's what I try. code: device = usb.core.find(find_all=True) for d in device: e ={} e['vid'] = hex(d.idVendor) e['pid'] = hex(d.idProduct) e['bus'] = d.bus e['address'] = d.address e['serial'] = usb.util.get_string(d, d.iSerialNumber) print(e) output: {'vid': '0x6cb', 'pid': '0x91', 'bus': 0, 'address': 1, 'serial': 'FTA8QAPB'} {'vid': '0x6cb', 'pid': '0x91', 'bus': 0, 'address': 2, 'serial': 'FTA8QAPB'}

Code: ctrl = SpiController(cs_count=1, turbo=True) Ftdi.add_custom_vendor(0x6cb) Ftdi.add_custom_product(0x6cb, 0x91) spi = SpiController(cs_count = 1) spi.configure('ftdi://::0:1/1')

slave = spi.get_port(cs=0, freq=12E6, mode=0) gpio = spi.get_gpio() b_io=GpioController() b_io.open_from_url('ftdi://::0:2/2', direction=0)

output: Traceback (most recent call last): File "C:\temp\Rev_05_dev\usbtools.py", line 408, in parseurl desc, = candidates[idx] IndexError: list index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "test.py", line 27, in b_io.open_from_url('ftdi://::0:2/2', direction=0) File "C:\temp\Rev_05_dev\gpio.py", line 79, in configure ftdi.open_bitbang_from_url(url, direction=direction, **kwargs) File "C:\temp\Rev_05_dev\ftdi.py", line 592, in open_bitbang_from_url devdesc, interface = self.get_identifiers(url) File "C:\temp\Rev_05_dev\ftdi.py", line 308, in get_identifiers cls.DEFAULT_VENDOR) File "C:\temp\Rev_05_dev\usbtools.py", line 412, in parse_url urlstr) usbtools.UsbToolsError: No USB device matches URL ftdi://::0:2/2

zhenqlin commented 5 years ago

I think usbtools.py find_all function use set for devs, that way sometime connect to channel A sometime B for my device. I hardcore ftdi.py bypass usbtools.py for open_mpsse_from_url and open_bitbang_from_url function looks like OK to connect now. Need continue move on to see if any other issues.

    addr = url.split('/')
    interface =  int(url.split('/')[-1])
    addr = addr[2].split(':')[-1]
    devices = usb.core.find(find_all=True)
    device = None
    for d in devices:
        if d.address == int(addr):
            device = d
    # devdesc, interface = self.get_identifiers(url)
    # device = UsbTools.get_device(devdesc)
eblot commented 5 years ago

Thanks for reply. Doesn't look like working. here's what I try. ...

Please try this, change to top level dir, and query the FTDI device list

 cd pyftdi
 PYTHONPATH=. python3 pyftdi/serialext/tests/pyterm.py -p ftdi:///?

what does that give you?

I'm not sure to understand your HW setup. How many FTDI devices are plugged in your host?

eblot commented 5 years ago

I think usbtools.py find_all function use set for devs, that way sometime connect to channel A sometime B for my device.

usbbools.py manages the devices (i.e. FTDI devices), not the interface on a device (i.e. 1 channel for FTDI232, 2 channels for a single FTDI2232, 4 channels for a single FTDI4232), so I do not get why channels would get mixed. usbtools.py selects a device, ftdi.py manages the channels.

zhenqlin commented 5 years ago

PYTHONPATH=. python3 pyftdi/serialext/tests/pyterm.py -p ftdi:///?

This test script is for Linux? I'm in windows,
from os import linesep, name as osname, stat , uname doesn't work, I took out uname and output is. No USB-Serial device has been detected.

I have only one device FT2232H, which has A and B two usb virtual port? and the different between them is the "address" . output: {'vid': '0x6cb', 'pid': '0x91', 'bus': 0, 'address': 1, 'serial': 'FTA8QAPB'} {'vid': '0x6cb', 'pid': '0x91', 'bus': 0, 'address': 2, 'serial': 'FTA8QAPB'}

zhenqlin commented 5 years ago

I plug my device into Linux pc. I see what you mean now. For Linux sees one device(same address) content two interface. But when I use Zadig install driver in windows 10, is two device (different address), one interface for each.

eblot commented 5 years ago

This test script is for Linux? Any unix/posix OS (Linux, FreeBSD, macOS, ...)

I'm in windows, Ok... it explains nearly everything them. Windows is a gigantic pile of crap in general, and especially when it comes to USB.

For some reason - as you've seen since - Windows (and/or Zadig?) thinks it is great to present a multiple interface USB device as several devices. This is a non sense (try to reset or unplug one w/o the other...). I'm not surprised this confuses PyFtdi.

I remember having checked how PyFtdi behaves on Windows a year or so ago - although PyFtdi is not supported on Windows - and eventually found a setup with Zadig where I was able to see the FTDI device had, at once:

  1. a single device with two interface, AND
  2. two devices with a single interface

I do not remember how I reached this state though - I simply cannot cope with Windows, it gets on my nerves as soon as I see the logo...

Using the first reported device solved the issue, and you do no need the usb_bus_address branch at all to make it work - as you have a serial number on your device.

I'll try to have a look at this M$ mess, but I cannot tell when. Meanwhile, if you can find the proper Zadig setup to make the device appears as it really is (one device, two interfaces), your problem should be solved.

eblot commented 5 years ago

In Zadig, if you check/uncheck the Options/Ignore hubs or composite parents menu item:

zadig-options

the FTDI2232 which appears a two unique devices:

zadig-default

now appears as a single device.

zadig-composite

Maybe this is the way to go.

I cannot help much more, as whether or not I install the Zadig driver, pyusb seems unable to find libusb, and I already lost too much time with this ugly OS.

zhenqlin commented 5 years ago

I know Linux developer always hate win 😊 Just like me, I want my software support both win and Linux, everything works on win but nothing works Linux.. OK! I change to Linux now, and lost a lot of time finally make the udev works.. If I have Linux questions in the future you can help, right??

eblot commented 5 years ago

OK! I change to Linux now, and lost a lot of time finally make the udev works..

Anything different than installation.html#debian-ubuntu-linux ?

If I have Linux questions in the future you can help, right??

I'll try - when I get some spare time :-)

BTW, did you try to setup the composite parent w/ Zadig?

RyanHope commented 5 years ago

I develop on both win and linux... I will try and get some windows testing in.

On Sun, Aug 25, 2019 at 5:49 AM Emmanuel Blot notifications@github.com wrote:

OK! I change to Linux now, and lost a lot of time finally make the udev works..

Anything different than installation.html#debian-ubuntu-linux https://eblot.github.io/pyftdi/installation.html#debian-ubuntu-linux ?

If I have Linux questions in the future you can help, right??

I'll try - when I get some spare time :-)

BTW, did you try to setup the composite parent w/ Zadig?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/eblot/pyftdi/issues/136?email_source=notifications&email_token=AABCNTOKOK3WWTQHELL2T2DQGJISTA5CNFSM4IHFE6I2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5CQE4Q#issuecomment-524616306, or mute the thread https://github.com/notifications/unsubscribe-auth/AABCNTM46OWIYYS2AYJCVP3QGJISTANCNFSM4IHFE6IQ .

eblot commented 5 years ago

Thanks Ryan. I'm unable to test it under Windows as pyusb fails to find Zadig's libusb for some reason.

eblot commented 5 years ago

Ok, I was failing to select "libusb-win32" as the driver to install. Anyway, selecting the composite parent vs. an individual interface gives the expected result:

C:\Users\eblot>pip3 install pyftdi
Collecting pyftdi
Requirement already satisfied: pyusb>=1.0.0 (1.0.2)
Requirement already satisfied: pyserial>=3.0 (3.4)
Installing collected packages: pyftdi
  Running setup.py install for pyftdi ... done
Successfully installed pyftdi-0.29.6

C:\Users\eblot>python
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) 
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyftdi import ftdi
>>> f = ftdi.Ftdi()
>>> f.open_from_url('ftdi:///?')
Available interfaces:
  ftdi://ftdi:2232/1   (Dual RS232-HS)
  ftdi://ftdi:2232/2   (Dual RS232-HS)

Please specify the USB device

Note that is using the "master" branch, not the usb_bus_address. I have not tried to communicate over SPI, but there should be not channel permutation using this approach:

I should add this to the documentation. Documenting for Windows, my dreams came true :-)

eblot commented 5 years ago

Using usb_bus_address branch:

>>> f.open_from_url('ftdi:///?')
Available interfaces:
  ftdi://ftdi:2232:0:1/1   (Dual RS232-HS)
  ftdi://ftdi:2232:0:1/2   (Dual RS232-HS)

Same bus, same address. At least...

eblot commented 5 years ago

I should add this to the documentation. Documenting for Windows, my dreams came true :-)

Done as d0b6366d

zhenqlin commented 5 years ago

Thanks Eblot, that works on windows..But I switch to Linux anyway :). FTDI sent me a MPSSE beta release, I modified their code little bit to support I2C with GPIO. Everything works on windows, so I have solution for win already. Now I need to make it works on Linux because my boss is a Linux guy....unfortunately the version of C code they sent me is for windows only..I have an option to make C code works on Linux or use pyftdi. Anyway...I'm still in debugging mode for gpio.. somehow gpio doesn't work as what I expected, I don't know what is going on yet, those pins is small hard to probe... For your GPIO port, looks like support 8 gpio only? if I want to control BDBUS 0-7 and BCBUS 0-7, how? I have an I2C device connect to BDBUS 0-1 for my board, I plan to use IO bit-bang approach since I don't care data rate fro that. But how to control BDBUS using your code?

zhenqlin commented 5 years ago

updated.. might be a issues with i2c.py? https://github.com/meierphil/pyftdi/tree/i2c_gpio_support

i2c = I2cController() i2c.configure('ftdi://::/2') i2c_slave =i2c.get_port(0x20) i2c_io = i2c.get_gpio() i2c_io.set_direction(0x0020, 0x0020) i2c_io.write(0x0020) print('I got BDBUS5 high here..') time.sleep(5) i2c_io.set_direction(0x0040, 0x0040) i2c_io.write(0x0040) print('BDBUS5 reset, I got low here..') time.sleep(1000)

looks like issues with this i2c.py. GPIO resets. but the same setting if change to spiController gpio does not reset, I think just need to work on the difference.

eblot commented 5 years ago

@RyanHope the bus:address selection is now implemented in the master branch, from e978f5e99f18b320b74598173e8f305463398899

@zhenqlin

  1. I think the Windows problem is addressed with the now-documented Zadig configuration process
  2. If you have some issue with I2C, please open a new, dedicated ticket. Be sure to test the v0.30.0 version first, released today. (fbfddb33ada5bd4c8a6cee448d2454a019a087e4)