def open(self, devclass, scheme, vdict, pdict, default_vendor): """Open the initialized serial port""" from serial import SerialException if self._port is None: raise SerialException("Port must be configured before use.") try: vendor, product, interface, sernum, ix = UsbTools.parse_url( self.portstr, devclass, scheme, vdict, pdict, default_vendor) except UsbToolsError, e: raise SerialException(str(e))
def open(self, vendor=0x0403, product=None, interface=1, index=0, serial=None, description=None): """Open a new interface to the specified FTDI device""" self.usb_dev = UsbTools.get_device(vendor, product, index, serial, description) # detect invalid interface as early as possible config = self.usb_dev.get_active_configuration() if interface > config.bNumInterfaces: raise FtdiError('No such FTDI port: %d' % interface) self._set_interface(config, interface) self.max_packet_size = self._get_max_packet_size() self._reset_device() self.set_latency_timer(self.LATENCY_MIN)
def test_list_devices(self): """List FTDI devices.""" vid = 0x403 vids = {'ftdi': vid} pids = { vid: { '230x': 0x6015, '232r': 0x6001, '232h': 0x6014, '2232h': 0x6010, '4232h': 0x6011, } } devs = UsbTools.list_devices('ftdi:///?', vids, pids, vid) self.assertEqual(len(devs), 6) ifmap = { 0x6001: 1, 0x6010: 2, 0x6011: 4, 0x6014: 1, 0x6015: 1 } for dev, desc in devs: strings = UsbTools.build_dev_strings('ftdi', vids, pids, [(dev, desc)]) self.assertEqual(len(strings), ifmap[dev.pid]) for url, _ in strings: parts, _ = UsbTools.parse_url(url, 'ftdi', vids, pids, vid) self.assertEqual(parts.vid, dev.vid) self.assertEqual(parts.pid, dev.pid) self.assertEqual(parts.bus, dev.bus) self.assertEqual(parts.address, dev.address) self.assertEqual(parts.sn, dev.sn) devs = UsbTools.list_devices('ftdi://:232h/?', vids, pids, vid) self.assertEqual(len(devs), 2) devs = UsbTools.list_devices('ftdi://:2232h/?', vids, pids, vid) self.assertEqual(len(devs), 1)
def id(self, ): # pylint: disable=invalid-name,too-many-branches,too-many-return-statements """Return a unique id for the detected chip, if any.""" # There are some times we want to trick the platform detection # say if a raspberry pi doesn't have the right ID, or for testing try: return os.environ["BLINKA_FORCECHIP"] except KeyError: # no forced chip, continue with testing! pass # Special cases controlled by environment var if os.environ.get("BLINKA_FT232H"): from pyftdi.usbtools import UsbTools # look for it based on PID/VID count = len(UsbTools.find_all([(0x0403, 0x6014)])) if count == 0: raise RuntimeError("BLINKA_FT232H environment variable " + "set, but no FT232H device found") return chips.FT232H if os.environ.get("BLINKA_MCP2221"): import hid # look for it based on PID/VID for dev in hid.enumerate(): if dev["vendor_id"] == 0x04D8 and dev["product_id"] == 0x00DD: return chips.MCP2221 raise RuntimeError("BLINKA_MCP2221 environment variable " + "set, but no MCP2221 device found") if os.environ.get("BLINKA_GREATFET"): import usb if usb.core.find(idVendor=0x1D50, idProduct=0x60E6) is not None: return chips.LPC4330 raise RuntimeError("BLINKA_GREATFET environment variable " + "set, but no GreatFET device found") if os.environ.get("BLINKA_NOVA"): return chips.BINHO platform = sys.platform if platform in ("linux", "linux2"): return self._linux_id() if platform == "esp8266": return chips.ESP8266 if platform == "samd21": return chips.SAMD21 if platform == "pyboard": return chips.STM32 # nothing found! return None
def format_ftdi_url(dev, interface=1): serialdesc = UsbTools.get_string(dev, dev.iSerialNumber) url = 'ftdi://' if platform == 'win32': # Because changes in pyftdi to support virtual port, we relie on bus / address instead of the sernum url += '0x%04x:0x%04x' % (dev.idVendor, dev.idProduct) url += ':%x:%x' % (dev.bus, dev.address) else: if serialdesc: url += '0x%04x:0x%04x:%s' % (dev.idVendor, dev.idProduct, serialdesc) else: url += '0x%04x:0x%04x' % (dev.idVendor, dev.idProduct) url += '/%d' % (interface) return url
def open(self, vendor, product, index=0, serial=None, interface=1): """Open a new interface to the specified FTDI device""" self.usb_dev = UsbTools.get_device(vendor, product, index, serial) try: self.usb_dev.set_configuration() except usb.core.USBError: pass # detect invalid interface as early as possible config = self.usb_dev.get_active_configuration() if interface > config.bNumInterfaces: raise FtdiError('No such FTDI port: %d' % interface) self._set_interface(config, interface) self.max_packet_size = self._get_max_packet_size() # Drain input buffer self.purge_buffers() self._reset_device() self.set_latency_timer(self.LATENCY_MIN)
def _esp32_find_console_port(): from pyftdi.usbtools import UsbTools # Try pyftdi first: devs = UsbTools.find_all([(0x0403, 0x6010)]) if devs: return "ftdi://ftdi:2232/2" # Fall back to /dev/cu... device: usb_paths = glob("/dev/cu.usbserial-*1") if usb_paths: return usb_paths[0] print( "Cannot find ESP32 console /dev/... nor ftdi:// path, please specify it manually using --port" ) exit(1)
def get_ftdi_devices(rtype=0): try: devs = Ftdi.list_devices() except: devs = [] if rtype==0: return len(devs) elif rtype==1: return devs elif rtype==2: try: res = UsbTools.build_dev_strings(Ftdi.SCHEME,Ftdi.VENDOR_IDS,Ftdi.PRODUCT_IDS,devs) except: res = [] # res.append( ('ftdi://ftdi:232h:3:9/1', '(Single RS232-HS)') ) # debug # res.append( ('ftdi://ftdi:232h:3:9/2', '(Single RS232-HS)') ) # debug res = sorted(res) return res
def open(self, devclass, scheme, vdict, pdict, default_vendor): """Open the initialized serial port""" from serial import SerialException if self._port is None: raise SerialException("Port must be configured before use.") try: vendor, product, interface, sernum, ix = UsbTools.parse_url( self.portstr, devclass, scheme, vdict, pdict, default_vendor) except UsbToolsError as e: raise SerialException(str(e)) try: self.udev = devclass() self.udev.open(vendor, product, interface, ix, sernum) self.flushOutput() self.flushInput() except IOError: raise SerialException('Unable to open USB port %s' % self.portstr) self._set_open_state(True) self._reconfigurePort() self._product = product
def id(self): # pylint: disable=invalid-name,too-many-branches,too-many-return-statements """Return a unique id for the detected chip, if any.""" # There are some times we want to trick the platform detection # say if a raspberry pi doesn't have the right ID, or for testing try: return os.environ['BLINKA_FORCECHIP'] except KeyError: # no forced chip, continue with testing! pass # Special cases controlled by environment var if os.environ.get('BLINKA_FT232H'): from pyftdi.usbtools import UsbTools # pylint: disable=import-error # look for it based on PID/VID count = len(UsbTools.find_all([(0x0403, 0x6014)])) if count == 0: raise RuntimeError('BLINKA_FT232H environment variable ' + \ 'set, but no FT232H device found') return chips.FT232H if os.environ.get('BLINKA_MCP2221'): import hid # pylint: disable=import-error # look for it based on PID/VID for dev in hid.enumerate(): if dev['vendor_id'] == 0x04D8 and dev['product_id'] == 0x00DD: return chips.MCP2221 raise RuntimeError('BLINKA_MCP2221 environment variable ' + \ 'set, but no MCP2221 device found') if os.environ.get('BLINKA_NOVA'): return chips.BINHO platform = sys.platform if platform in ('linux', 'linux2'): return self._linux_id() if platform == 'esp8266': return chips.ESP8266 if platform == 'samd21': return chips.SAMD21 if platform == 'pyboard': return chips.STM32 # nothing found! return None
def main(): """Entry point.""" debug = False try: argparser = ArgumentParser(description=modules[__name__].__doc__) argparser.add_argument('-P', '--vidpid', action='append', help='specify a custom VID:PID device ID, ' 'may be repeated') argparser.add_argument('-V', '--virtual', type=FileType('r'), help='use a virtual device, specified as YaML') argparser.add_argument('-v', '--verbose', action='count', default=0, help='increase verbosity') argparser.add_argument('-d', '--debug', action='store_true', help='enable debug mode') args = argparser.parse_args() debug = args.debug loglevel = max(DEBUG, ERROR - (10 * args.verbose)) loglevel = min(ERROR, loglevel) if debug: formatter = Formatter( '%(asctime)s.%(msecs)03d %(name)-20s ' '%(message)s', '%H:%M:%S') else: formatter = Formatter('%(message)s') FtdiLogger.set_formatter(formatter) FtdiLogger.set_level(loglevel) FtdiLogger.log.addHandler(StreamHandler(stderr)) if args.virtual: from pyftdi.usbtools import UsbTools # Force PyUSB to use PyFtdi test framework for USB backends UsbTools.BACKENDS = ('pyftdi.tests.backend.usbvirt', ) # Ensure the virtual backend can be found and is loaded backend = UsbTools.find_backend() loader = backend.create_loader()() loader.load(args.virtual) try: add_custom_devices(Ftdi, args.vidpid) except ValueError as exc: argparser.error(str(exc)) Ftdi.show_devices() except (ImportError, IOError, NotImplementedError, ValueError) as exc: print('\nError: %s' % exc, file=stderr) if debug: print(format_exc(chain=False), file=stderr) exit(1) except KeyboardInterrupt: exit(2)
def main(): """Main routine""" debug = False try: argparser = ArgumentParser(description=modules[__name__].__doc__) argparser.add_argument('device', nargs='?', default='ftdi:///?', help='serial port device name') argparser.add_argument('-x', '--hexdump', action='store_true', help='dump EEPROM content as ASCII') argparser.add_argument('-X', '--hexblock', type=int, help='dump EEPROM as indented hexa blocks') argparser.add_argument('-i', '--input', type=FileType('rt'), help='input ini file to load EEPROM content') argparser.add_argument('-l', '--load', default='all', choices=('all', 'raw', 'values'), help='section(s) to load from input file') argparser.add_argument('-o', '--output', type=FileType('wt'), help='output ini file to save EEPROM content') argparser.add_argument('-s', '--serial-number', help='set serial number') argparser.add_argument('-m', '--manufacturer', help='set manufacturer name') argparser.add_argument('-p', '--product', help='set product name') argparser.add_argument('-c', '--config', action='append', help='change/configure a property ' 'as key=value pair') argparser.add_argument('-e', '--erase', action='store_true', help='erase the whole EEPROM content') argparser.add_argument('-u', '--update', action='store_true', help='perform actual update, use w/ care') argparser.add_argument('-P', '--vidpid', action='append', help='specify a custom VID:PID device ID, ' 'may be repeated') argparser.add_argument('-V', '--virtual', type=FileType('r'), help='use a virtual device, specified as YaML') argparser.add_argument('-v', '--verbose', action='count', default=0, help='increase verbosity') argparser.add_argument('-d', '--debug', action='store_true', help='enable debug mode') args = argparser.parse_args() debug = args.debug if not args.device: argparser.error('Serial device not specified') loglevel = max(DEBUG, ERROR - (10 * args.verbose)) loglevel = min(ERROR, loglevel) if debug: formatter = Formatter( '%(asctime)s.%(msecs)03d %(name)-20s ' '%(message)s', '%H:%M:%S') else: formatter = Formatter('%(message)s') FtdiLogger.set_formatter(formatter) FtdiLogger.set_level(loglevel) FtdiLogger.log.addHandler(StreamHandler(stderr)) if args.virtual: from pyftdi.usbtools import UsbTools # Force PyUSB to use PyFtdi test framework for USB backends UsbTools.BACKENDS = ('pyftdi.tests.backend.usbvirt', ) # Ensure the virtual backend can be found and is loaded backend = UsbTools.find_backend() loader = backend.create_loader()() loader.load(args.virtual) try: add_custom_devices(Ftdi, args.vidpid) except ValueError as exc: argparser.error(str(exc)) eeprom = FtdiEeprom() eeprom.open(args.device) if args.erase: eeprom.erase() if args.input: eeprom.load_config(args.input, args.load) if args.serial_number: eeprom.set_serial_number(args.serial_number) if args.manufacturer: eeprom.set_manufacturer_name(args.manufacturer) if args.product: eeprom.set_product_name(args.product) for conf in args.config or []: if conf == '?': helpstr = ', '.join(sorted(eeprom.properties)) print( fill(helpstr, initial_indent=' ', subsequent_indent=' ')) exit(1) for sep in ':=': if sep in conf: name, value = conf.split(sep, 1) if not value: argparser.error('Configuration %s without value' % conf) helpio = StringIO() eeprom.set_property(name, value, helpio) helpstr = helpio.getvalue() if helpstr: print( fill(helpstr, initial_indent=' ', subsequent_indent=' ')) exit(1) break else: argparser.error('Missing name:value separator in %s' % conf) if args.hexdump: print(hexdump(eeprom.data)) if args.hexblock is not None: indent = ' ' * args.hexblock for pos in range(0, len(eeprom.data), 16): hexa = ' '.join( ['%02x' % x for x in eeprom.data[pos:pos + 16]]) print(indent, hexa, sep='') if args.update: if eeprom.commit(False): eeprom.reset_device() if args.verbose > 0: eeprom.dump_config() if args.output: eeprom.save_config(args.output) except (ImportError, IOError, NotImplementedError, ValueError) as exc: print('\nError: %s' % exc, file=stderr) if debug: print(format_exc(chain=False), file=stderr) exit(1) except KeyboardInterrupt: exit(2)
def id( self, ) -> Optional[ str ]: # pylint: disable=invalid-name,too-many-branches,too-many-return-statements """Return a unique id for the detected chip, if any.""" # There are some times we want to trick the platform detection # say if a raspberry pi doesn't have the right ID, or for testing # Caching if self._chip_id: return self._chip_id if getattr(os, "environ", None) is not None: try: return os.environ["BLINKA_FORCECHIP"] except KeyError: # no forced chip, continue with testing! pass # Special cases controlled by environment var if os.environ.get("BLINKA_FT232H"): from pyftdi.usbtools import UsbTools # look for it based on PID/VID count = len(UsbTools.find_all([(0x0403, 0x6014)])) if count == 0: raise RuntimeError( "BLINKA_FT232H environment variable " + "set, but no FT232H device found" ) self._chip_id = chips.FT232H return self._chip_id if os.environ.get("BLINKA_FT2232H"): from pyftdi.usbtools import UsbTools # look for it based on PID/VID count = len(UsbTools.find_all([(0x0403, 0x6010)])) if count == 0: raise RuntimeError( "BLINKA_FT2232H environment variable " + "set, but no FT2232H device found" ) self._chip_id = chips.FT2232H return self._chip_id if os.environ.get("BLINKA_MCP2221"): import hid # look for it based on PID/VID for dev in hid.enumerate(): if dev["vendor_id"] == 0x04D8 and dev["product_id"] == 0x00DD: self._chip_id = chips.MCP2221 return self._chip_id raise RuntimeError( "BLINKA_MCP2221 environment variable " + "set, but no MCP2221 device found" ) if os.environ.get("BLINKA_U2IF"): import hid # look for it based on PID/VID for dev in hid.enumerate(): vendor = dev["vendor_id"] product = dev["product_id"] # NOTE: If any products are added here, they need added # to _rp2040_u2if_id() in board.py as well. if ( # Raspberry Pi Pico vendor == 0xCAFE and product == 0x4005 ) or ( # Feather RP2040 # Itsy Bitsy RP2040 # QT Py RP2040 # QT2040 Trinkey # MacroPad RP2040 vendor == 0x239A and product in (0x00F1, 0x00FD, 0x00F7, 0x0109, 0x0107) ): self._chip_id = chips.RP2040_U2IF return self._chip_id raise RuntimeError( "BLINKA_U2IF environment variable " + "set, but no compatible device found" ) if os.environ.get("BLINKA_GREATFET"): import usb if usb.core.find(idVendor=0x1D50, idProduct=0x60E6) is not None: self._chip_id = chips.LPC4330 return self._chip_id raise RuntimeError( "BLINKA_GREATFET environment variable " + "set, but no GreatFET device found" ) if os.environ.get("BLINKA_NOVA"): self._chip_id = chips.BINHO return self._chip_id platform = sys.platform if platform in ("linux", "linux2"): self._chip_id = self._linux_id() return self._chip_id if platform == "esp8266": self._chip_id = chips.ESP8266 return self._chip_id if platform == "samd21": self._chip_id = chips.SAMD21 return self._chip_id if platform == "pyboard": self._chip_id = chips.STM32F405 return self._chip_id if platform == "rp2": self._chip_id = chips.RP2040 return self._chip_id # nothing found! return None
def main(): """Main routine""" debug = False try: default_device = get_default_device() argparser = ArgumentParser(description=modules[__name__].__doc__) argparser.add_argument('-f', '--fullmode', dest='fullmode', action='store_true', help='use full terminal mode, exit with ' '[Ctrl]+B') argparser.add_argument('device', nargs='?', default=default_device, help='serial port device name (default: %s)' % default_device) argparser.add_argument('-b', '--baudrate', help='serial port baudrate (default: %d)' % MiniTerm.DEFAULT_BAUDRATE, default='%s' % MiniTerm.DEFAULT_BAUDRATE) argparser.add_argument('-w', '--hwflow', action='store_true', help='hardware flow control') argparser.add_argument('-e', '--localecho', action='store_true', help='local echo mode (print all typed chars)') argparser.add_argument('-r', '--crlf', action='count', default=0, help='prefix LF with CR char, use twice to ' 'replace all LF with CR chars') argparser.add_argument('-l', '--loopback', action='store_true', help='loopback mode (send back all received ' 'chars)') argparser.add_argument('-s', '--silent', action='store_true', help='silent mode') argparser.add_argument('-P', '--vidpid', action='append', help='specify a custom VID:PID device ID, ' 'may be repeated') argparser.add_argument('-V', '--virtual', type=FileType('r'), help='use a virtual device, specified as YaML') argparser.add_argument('-v', '--verbose', action='count', help='increase verbosity') argparser.add_argument('-d', '--debug', action='store_true', help='enable debug mode') args = argparser.parse_args() debug = args.debug if not args.device: argparser.error('Serial device not specified') loglevel = max(DEBUG, ERROR - (10 * (args.verbose or 0))) loglevel = min(ERROR, loglevel) if debug: formatter = Formatter( '%(asctime)s.%(msecs)03d %(name)-20s ' '%(message)s', '%H:%M:%S') else: formatter = Formatter('%(message)s') FtdiLogger.set_formatter(formatter) FtdiLogger.set_level(loglevel) FtdiLogger.log.addHandler(StreamHandler(stderr)) if args.virtual: from pyftdi.usbtools import UsbTools # Force PyUSB to use PyFtdi test framework for USB backends UsbTools.BACKENDS = ('pyftdi.tests.backend.usbvirt', ) # Ensure the virtual backend can be found and is loaded backend = UsbTools.find_backend() loader = backend.create_loader()() loader.load(args.virtual) try: add_custom_devices(Ftdi, args.vidpid) except ValueError as exc: argparser.error(str(exc)) miniterm = MiniTerm(device=args.device, baudrate=to_bps(args.baudrate), parity='N', rtscts=args.hwflow, debug=args.debug) miniterm.run(args.fullmode, args.loopback, args.silent, args.localecho, args.crlf) except (IOError, ValueError) as exc: print('\nError: %s' % exc, file=stderr) if debug: print(format_exc(chain=False), file=stderr) sysexit(1) except KeyboardInterrupt: sysexit(2)
def close(self): """Close the FTDI interface""" self.set_latency_timer(self.LATENCY_MAX) UsbTools.release_device(self.usb_dev)
def find_all(vps, nocache=False): """Find all devices that match the vendor/product pairs of the vps list.""" return UsbTools.find_all(vps, nocache)
if __name__ == '__main__': parser = argparse.ArgumentParser(description='Xyloni VCCIO adjust') parser.add_argument('VCC_IO1', choices=['3.3V', '2.5V', '1.8V'], help='VCC_IO1 voltage') parser.add_argument('VCC_IO2', choices=['3.3V', '2.5V', '1.8V'], help='VCC_IO2 voltage') # URL is based on which exact FTDI chipset used in cable # see 'https://eblot.github.io/pyftdi/urlscheme.html' for more details if platform == "win32": default_url = "ftdi:///4" devices = UsbTools._find_devices(0x0403, 0x6011, True) for dev in devices: if get_interface_index(dev) == 3: default_url = format_ftdi_url(dev) else: default_url = "ftdi:///4" parser.add_argument('-u', '--url', default=default_url, help='FTDI URL') # run parser args = parser.parse_args() gpio = GpioController() gpio.configure(args.url, direction=0x0F) setting = 0x0F # start with 3.3V both VCC_IO1 and VCC_IO2
def setUpClass(cls): cls.loader = MockLoader() with open('pyftdi/tests/resources/ft232h.yaml', 'rb') as yfp: cls.loader.load(yfp) UsbTools.flush_cache()
def test_enumerate(self): """Enumerate FTDI devices.""" ftdis = [(0x403, pid) for pid in (0x6001, 0x6010, 0x6011, 0x6014, 0x6015)] count = len(UsbTools.find_all(ftdis)) self.assertEqual(count, 6)