示例#1
0
    def test_output_gpio(self):
        """Simple test to demonstrate ouput bit-banging on CBUS.

           You need a CBUS-capable FTDI (FT232R/FT232H/FT230X/FT231X), whose
           EEPROM has been configured to support GPIOs on CBUS0 and CBUS3.

           Hard-wiring is required to run this test:
           * CBUS0 (output) should be connected to CTS (input)
           * CBUS3 (output) should be connected to DSR (input)
        """
        ftdi = Ftdi()
        ftdi.open_from_url(self.url)
        # sanity check: device should support CBUS feature
        self.assertEqual(ftdi.has_cbus, True)
        eeprom = FtdiEeprom()
        eeprom.connect(ftdi)
        # sanity check: device should have been configured for CBUS GPIOs
        self.assertEqual(eeprom.cbus_mask & 0b1001, 0b1001)
        # configure CBUS0 and CBUS3 as output
        ftdi.set_cbus_direction(0b1001, 0b1001)
        # no input pin available
        self.assertRaises(FtdiError, ftdi.get_cbus_gpio)
        for cycle in range(40):
            value = cycle & 0x3
            # CBUS0 and CBUS3
            cbus = ((value & 0x2) << 2) | value & 0x1
            # for now, need a digital/logic analyzer to validate output
            ftdi.set_cbus_gpio(cbus)
            # CBUS0 is connected to CTS, CBUS3 to DSR
            # need to inverse logical level as RS232 uses negative logic
            sig = int(not ftdi.get_cts()) | (int(not ftdi.get_dsr()) << 1)
            self.assertEqual(value, sig)
示例#2
0
    def test_input_gpio(self):
        """Simple test to demonstrate input bit-banging on CBUS.

           You need a CBUS-capable FTDI (FT232R/FT232H/FT230X/FT231X), whose
           EEPROM has been configured to support GPIOs on CBUS0 and CBUS3.

           Hard-wiring is required to run this test:
           * CBUS0 (input) should be connected to RTS (output)
           * CBUS3 (input) should be connected to DTR (output)
        """
        ftdi = Ftdi()
        ftdi.open_from_url(self.url)
        # sanity check: device should support CBUS feature
        self.assertEqual(ftdi.has_cbus, True)
        eeprom = FtdiEeprom()
        eeprom.connect(ftdi)
        # sanity check: device should have been configured for CBUS GPIOs
        self.assertEqual(eeprom.cbus_mask & 0b1001, 0b1001)
        # configure CBUS0 and CBUS3 as input
        ftdi.set_cbus_direction(0b1001, 0b0000)
        # no output pin available
        self.assertRaises(FtdiError, ftdi.set_cbus_gpio, 0)
        for cycle in range(40):
            rts = bool(cycle & 0x1)
            dtr = bool(cycle & 0x2)
            ftdi.set_rts(rts)
            ftdi.set_dtr(dtr)
            # need to inverse logical level as RS232 uses negative logic
            cbus = ~ftdi.get_cbus_gpio()
            sig = (cbus & 0x1) | ((cbus & 0x8) >> 2)
            value = cycle & 0x3
            self.assertEqual(value, sig)
示例#3
0
 def _decode_cbus_x0600(self) -> None:
     cbus_gpio = 0
     cbus_active = 0
     bix = 0
     while True:
         value = self._parent.eeprom[0x14 + bix]
         low, high = value & 0x0F, value >> 4
         bit = 1 << (2 * bix)
         if FtdiEeprom.CBUS(low).name == 'GPIO':
             cbus_gpio |= bit
             cbus_active |= bit
         if bix == 2:
             break
         bit <<= 1
         if FtdiEeprom.CBUS(high).name == 'GPIO':
             cbus_gpio |= bit
             cbus_active |= bit
         bix += 1
     mask = (1 << self._parent.properties.cbuswidth) - 1
     self._cbusp_gpio = cbus_gpio & mask
     self._cbusp_force = 0
     self._cbusp_active = cbus_active & mask
     self.log.debug('x0600 config gpio %s, force %s, active %s',
                    f'{self._cbusp_gpio:04b}', f'{self._cbusp_force:04b}',
                    f'{self._cbusp_active:04b}')
示例#4
0
 def test_mirror_serial(self):
     """Verify serial string is properly duplicated across the 2 eeprom
         sectors
     """
     eeprom = FtdiEeprom()
     eeprom.enable_mirroring(True)
     eeprom.open(self.url, ignore=True)
     eeprom.erase()
     eeprom.set_serial_number(self.TEST_SN)
     self._check_for_mirrored_eeprom_contents(eeprom)
示例#5
0
 def test_mirror_product(self):
     """Verify product string is properly duplicated across the 2 eeprom
         sectors
     """
     eeprom = FtdiEeprom()
     eeprom.enable_mirroring(True)
     eeprom.open(self.url, ignore=True)
     eeprom.erase()
     eeprom.set_product_name(self.TEST_PROD_NAME)
     self._check_for_mirrored_eeprom_contents(eeprom)
示例#6
0
 def test_mirror_manufacturer(self):
     """Verify manufacturer string is properly duplicated across the 2
         eeprom sectors
     """
     eeprom = FtdiEeprom()
     eeprom.enable_mirroring(True)
     eeprom.open(self.url, ignore=True)
     eeprom.erase()
     eeprom.set_manufacturer_name(self.TEST_MANU_NAME)
     self._check_for_mirrored_eeprom_contents(eeprom)
示例#7
0
 def _decode_cbus_x0900(self) -> None:
     cbus_gpio = 0
     cbus_force = 0
     cbus_active = 0
     for bix in range(5):
         value = self._parent.eeprom[0x18 + bix]
         low, high = value & 0x0F, value >> 4
         bit = 1 << 2 * bix
         if FtdiEeprom.CBUSH(low).name == 'GPIO':
             cbus_gpio |= bit
             cbus_active |= bit
         elif FtdiEeprom.CBUSH(low).name == 'DRIVE0':
             cbus_force &= ~bit  # useless, for code symmetry
             cbus_active |= bit
         elif FtdiEeprom.CBUSH(low).name == 'DRIVE1':
             cbus_force |= bit
             cbus_active |= bit
         bit <<= 1
         if FtdiEeprom.CBUSH(high).name == 'GPIO':
             cbus_gpio |= bit
             cbus_active |= bit
         elif FtdiEeprom.CBUSH(high).name == 'DRIVE0':
             cbus_force &= ~bit  # useless, for code symmetry
             cbus_active |= bit
         elif FtdiEeprom.CBUSH(high).name == 'DRIVE1':
             cbus_force |= bit
             cbus_active |= bit
     mask = (1 << self._parent.properties.cbuswidth) - 1
     self._cbusp_gpio = cbus_gpio & mask
     self._cbusp_force = cbus_force & mask
     self._cbusp_active = cbus_active & mask
     self._cbus_map = {0: 5, 1: 6, 2: 8, 3: 9}
     self.log.debug('x0900 config gpio %s, force %s, active %s',
                    f'{self._cbusp_gpio:04b}', f'{self._cbusp_force:04b}',
                    f'{self._cbusp_active:04b}')
示例#8
0
 def _decode_cbus_x1000(self) -> None:
     cbus_gpio = 0
     cbus_force = 0
     cbus_active = 0
     for bix in range(4):
         value = self._parent.eeprom[0x1A + bix]
         bit = 1 << bix
         if FtdiEeprom.CBUSX(value).name == 'GPIO':
             cbus_gpio |= bit
             cbus_active |= bit
         elif FtdiEeprom.CBUSX(value).name == 'DRIVE0':
             cbus_force &= ~bit  # useless, for code symmetry
             cbus_active |= bit
         elif FtdiEeprom.CBUSX(value).name == 'DRIVE1':
             cbus_force |= bit
             cbus_active |= bit
     mask = (1 << self._parent.properties.cbuswidth) - 1
     self._cbusp_gpio = cbus_gpio & mask
     self._cbusp_force = cbus_force & mask
     self._cbusp_active = cbus_active & mask
     self.log.debug('x1000 config gpio %s, force %s, active %s',
                    f'{self._cbusp_gpio:04b}', f'{self._cbusp_force:04b}',
                    f'{self._cbusp_active:04b}')
示例#9
0
    def test_compute_size_detects_mirror(self):
        """Verify the eeproms internal _compute_size method
            returns the correct bool value when it detects an eeprom mirror
        """
        eeprom = FtdiEeprom()
        eeprom.open(self.url, ignore=True)
        _, mirrored = eeprom._compute_size([])
        self.assertFalse(mirrored)
        test_buf = bytearray(eeprom.size)
        sector_mid = eeprom.size // 2
        for ii in range(sector_mid):
            test_buf[ii] = ii % 255
            test_buf[sector_mid+ii] = test_buf[ii]
        _, mirrored = eeprom._compute_size(bytes(test_buf))
        self.assertTrue(mirrored)

        # change one byte and confirm failure
        test_buf[eeprom.size - 2] = test_buf[eeprom.size - 2] - 1
        _, mirrored = eeprom._compute_size(bytes(test_buf))
        self.assertFalse(mirrored)
示例#10
0
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('-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('-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('-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))

        eeprom = FtdiEeprom()
        eeprom.open(args.device)
        if args.erase:
            eeprom.erase()
        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)
        if args.hexdump:
            print(hexdump(eeprom.data))
        if args.update:
            eeprom.commit(False)
        if args.verbose > 0:
            eeprom.dump_config()
        if args.output:
            eeprom.save_config(args.output)

    except (IOError, ValueError) as exc:
        print('\nError: %s' % exc, file=stderr)
        if debug:
            print(format_exc(chain=False), file=stderr)
        exit(1)
    except KeyboardInterrupt:
        exit(2)
示例#11
0
 def test_ft232h(self):
     with open('pyftdi/tests/resources/ft232h_x2.yaml', 'rb') as yfp:
         self.loader.load(yfp)
     eeprom = FtdiEeprom()
     eeprom.open('ftdi://::FT1ABC1/1', ignore=True)
     eeprom.erase()
     eeprom.initialize()
     # default EEPROM config does not have any CBUS configured as GPIO
     self.assertEqual(eeprom.cbus_pins, [])
     self.assertEqual(eeprom.cbus_mask, 0)
     eeprom.set_property('cbus_func_6', 'gpio')
     eeprom.set_property('cbus_func_9', 'gpio')
     # not yet committed
     self.assertEqual(eeprom.cbus_pins, [])
     self.assertEqual(eeprom.cbus_mask, 0)
     eeprom.sync()
     # committed
     self.assertEqual(eeprom.cbus_pins, [6, 9])
     self.assertEqual(eeprom.cbus_mask, 0xA)
     eeprom.set_property('cbus_func_5', 'gpio')
     eeprom.set_property('cbus_func_8', 'gpio')
     eeprom.sync()
     self.assertEqual(eeprom.cbus_pins, [5, 6, 8, 9])
     self.assertEqual(eeprom.cbus_mask, 0xF)
     # pin1 and pin3 is not configurable as GPIO
     self.assertRaises(ValueError, eeprom.set_property, 'cbus_func_1',
                       'gpio')
     self.assertRaises(ValueError, eeprom.set_property, 'cbus_func_3',
                       'gpio')
     eeprom.close()
示例#12
0
    def test_mirror_properties(self):
        """Check FtdiEeprom properties are accurate for a device that can
            mirror
        """
        # properties should work regardless of if the mirror option is set
        # or not
        eeprom = FtdiEeprom()
        eeprom.open(self.url, ignore=True)
        self.assertTrue(eeprom.has_mirroring)
        self.assertEqual(eeprom.size // 2, eeprom.mirror_sector)
        eeprom.close()

        mirrored_eeprom = FtdiEeprom()
        mirrored_eeprom.enable_mirroring(True)
        mirrored_eeprom.open(self.url, ignore=True)
        self.assertTrue(mirrored_eeprom.has_mirroring)
        self.assertEqual(mirrored_eeprom.size // 2,
            mirrored_eeprom.mirror_sector)
        mirrored_eeprom.close()
示例#13
0
    def test_compute_size_does_not_mirror(self):
        """Verify the eeproms internal _compute_size method returns the correct
           bool value when it detects no mirroring.
        """
        eeprom = FtdiEeprom()
        eeprom.open(self.url, ignore=True)
        _, mirrored = eeprom._compute_size([])
        self.assertFalse(mirrored)
        eeprom.close()

        eeprom = FtdiEeprom()
        eeprom.open(self.url, ignore=False)
        _, mirrored = eeprom._compute_size([])
        self.assertFalse(mirrored)
        eeprom.close()
示例#14
0
 def test_mirror_properties(self):
     """Check FtdiEeprom properties are accurate for a device that can not
        mirror.
     """
     # properties should work regardless of if the mirror option is set
     # or not
     eeprom = FtdiEeprom()
     eeprom.open(self.url, ignore=True)
     self.assertFalse(eeprom.has_mirroring)
     with self.assertRaises(FtdiError):
         eeprom.mirror_sector
     eeprom.close()
     # even if mirroring is enabled, should still stay false
     mirrored_eeprom = FtdiEeprom()
     mirrored_eeprom.enable_mirroring(True)
     mirrored_eeprom.open(self.url, ignore=True)
     self.assertFalse(mirrored_eeprom.has_mirroring)
     with self.assertRaises(FtdiError):
         eeprom.mirror_sector
     mirrored_eeprom.close()
示例#15
0
    def test_varstr_combinations(self):
        """Verify various combinations of var strings are properly duplicated
            across the 2 eeprom sectors
        """
        eeprom = FtdiEeprom()
        eeprom.enable_mirroring(True)
        eeprom.open(self.url, ignore=True)

        # manu + prod str
        eeprom.erase()
        eeprom.set_manufacturer_name(self.TEST_MANU_NAME)
        eeprom.set_product_name(self.TEST_PROD_NAME)
        self._check_for_mirrored_eeprom_contents(eeprom)

        # manu + sn str
        eeprom.erase()
        eeprom.set_manufacturer_name(self.TEST_MANU_NAME)
        eeprom.set_serial_number(self.TEST_SN)
        self._check_for_mirrored_eeprom_contents(eeprom)

        # prod + sn str
        eeprom.erase()
        eeprom.set_manufacturer_name(self.TEST_PROD_NAME)
        eeprom.set_serial_number(self.TEST_SN)
        self._check_for_mirrored_eeprom_contents(eeprom)

        # manu + prod + sn str
        eeprom.erase()
        eeprom.set_manufacturer_name(self.TEST_MANU_NAME)
        eeprom.set_manufacturer_name(self.TEST_PROD_NAME)
        eeprom.set_serial_number(self.TEST_SN)
        self._check_for_mirrored_eeprom_contents(eeprom)
示例#16
0
 def test_ft230x(self):
     with open('pyftdi/tests/resources/ft230x.yaml', 'rb') as yfp:
         self.loader.load(yfp)
     eeprom = FtdiEeprom()
     eeprom.open('ftdi:///1')
     # default EEPROM config does not have any CBUS configured as GPIO
     self.assertEqual(eeprom.cbus_pins, [])
     self.assertEqual(eeprom.cbus_mask, 0)
     # enable CBUS1 and CBUS3 as GPIO
     eeprom.set_property('cbus_func_1', 'gpio')
     eeprom.set_property('cbus_func_3', 'gpio')
     eeprom.sync()
     self.assertEqual(eeprom.cbus_pins, [1, 3])
     self.assertEqual(eeprom.cbus_mask, 0xA)
     # enable CBUS0 and CBUS2 as GPIO
     eeprom.set_property('cbus_func_0', 'gpio')
     eeprom.set_property('cbus_func_2', 'gpio')
     # not yet committed
     self.assertEqual(eeprom.cbus_pins, [1, 3])
     self.assertEqual(eeprom.cbus_mask, 0xA)
     eeprom.sync()
     # committed
     self.assertEqual(eeprom.cbus_pins, [0, 1, 2, 3])
     self.assertEqual(eeprom.cbus_mask, 0xF)
     # invalid CBUS pin
     self.assertRaises(ValueError, eeprom.set_property, 'cbus_func_4',
                       'gpio')
     # invalid pin function
     self.assertRaises(ValueError, eeprom.set_property, 'cbus_func_0',
                       'gpio_')
     # invalid pin
     self.assertRaises(ValueError, eeprom.set_property, 'cbus_func', 'gpio')
     # valid alternative mode
     eeprom.set_property('cbus_func_0', 'txled')
     eeprom.set_property('cbus_func_1', 'rxled')
     eeprom.sync()
     self.assertEqual(eeprom.cbus_pins, [2, 3])
     self.assertEqual(eeprom.cbus_mask, 0xC)
     eeprom.close()
示例#17
0
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)
示例#18
0
def load_eeprom(vid, pid, sn):
    ftdi = Ftdi()
    eeprom = FtdiEeprom()
    ftdi.open(vid, pid, serial=sn)
    eeprom.connect(ftdi)
    return eeprom