Example #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)
Example #2
0
 def __init__(self):
     self._ftdi = Ftdi()
     self._lock = Lock()
     self.log = getLogger('pyftdi.i2c')
     self._gpio_port = None
     self._gpio_dir = 0
     self._gpio_low = 0
     self._gpio_mask = 0
     self._i2c_mask = 0
     self._wide_port = False
     self._slaves = {}
     self._retry_count = self.RETRY_COUNT
     self._frequency = 0.0
     self._immediate = (Ftdi.SEND_IMMEDIATE, )
     self._read_bit = (Ftdi.READ_BITS_PVE_MSB, 0)
     self._read_byte = (Ftdi.READ_BYTES_PVE_MSB, 0, 0)
     self._write_byte = (Ftdi.WRITE_BYTES_NVE_MSB, 0, 0)
     self._nack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.HIGH)
     self._ack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.LOW)
     self._ck_delay = 1
     self._tristate = None
     self._tx_size = 1
     self._rx_size = 1
     self._ck_hd_sta = 0
     self._ck_su_sto = 0
     self._ck_idle = 0
Example #3
0
    def __init__(self, ftdi_pid='232r', serial_num=None, laser_pin=PIN_CTS):
        """Inits LaserPointer object.

        Initializes a LaserPointer object by constructing an Ftdi object and opening the desired
        FTDI device. Configures the FTDI device to bitbang mode.

        Args:
            ftdi_pid: Product ID string for the FTDI device.
            serial_num: String containing the serial number of the FTDI device. If None, any
                serial number will be accepted.
            laser_pin: Integer bit mask with a single bit set corresponding to the pin on the FTDI
                device that controls the laser pointer.
        """
        self.laser_pin = laser_pin

        self.ftdi = Ftdi()

        self.ftdi.open_bitbang(
            vendor=Ftdi.VENDOR_IDS['ftdi'],
            product=Ftdi.PRODUCT_IDS[Ftdi.FTDI_VENDOR][ftdi_pid],
            serial=serial_num,        # serial number of FT232RQ in the laser FTDI cable
            latency=Ftdi.LATENCY_MAX, # 255ms; reduce if necessary (at cost of higher CPU usage)
        )

        # set laser_pin as output, all others as inputs
        self.ftdi.set_bitmode(self.laser_pin, Ftdi.BitMode.BITBANG)
        assert self.ftdi.bitbang_enabled

        # make sure laser is disabled by default
        self.set(False)
Example #4
0
 def __init__(self, silent_clock=False, cs_count=4, turbo=True):
     self._ftdi = Ftdi()
     self._cs_bits = (((SpiController.CS_BIT << cs_count) - 1)
                      & ~(SpiController.CS_BIT - 1))
     self._ports = [None] * cs_count
     self._direction = (self._cs_bits | SpiController.DO_BIT
                        | SpiController.SCK_BIT)
     self._turbo = turbo
     self._cs_high = Array('B')
     if self._turbo:
         if silent_clock:
             # Set SCLK as input to avoid emitting clock beats
             self._cs_high.extend([
                 Ftdi.SET_BITS_LOW, self._cs_bits,
                 self._direction & ~SpiController.SCK_BIT
             ])
         # /CS to SCLK delay, use 8 clock cycles as a HW tempo
         self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xff])
     # Restore idle state
     self._cs_high.extend(
         [Ftdi.SET_BITS_LOW, self._cs_bits, self._direction])
     if not self._turbo:
         self._cs_high.append(Ftdi.SEND_IMMEDIATE)
     self._immediate = Array('B', [Ftdi.SEND_IMMEDIATE])
     self._frequency = 0.0
Example #5
0
    def open(self, baud=None):
        if self.b_ftdi_obj:
            if baud is not None:
                self.ser.set_baudrate(baud)
            return self.isopen

        if self.ser is not None:
            if self.isopen: self.close()

        if self.ser is None:
            self.ser = Ftdi()

        self.isopen = False
        try:
            self.ser.open(vendor=self.VENDOR_ID,
                          product=self.pid,
                          interface=self.devno)
            self.isopen = True
        except:
            pass

        if baud is None:
            baud = self.self.BAUD_DEFAULT

        self.ser.set_baudrate(baud)

        return self.isopen
Example #6
0
 def __init__(self):
     self._ftdi = Ftdi()
     self.log = getLogger('pyftdi.i2c')
     self._slaves = {}
     self._frequency = 0.0
     self._direction = I2cController.SCL_BIT | I2cController.SDA_O_BIT
     self._immediate = (Ftdi.SEND_IMMEDIATE, )
     self._idle = (Ftdi.SET_BITS_LOW, self.IDLE, self._direction)
     data_low = (Ftdi.SET_BITS_LOW, self.IDLE & ~self.SDA_O_BIT,
                 self._direction)
     clock_low_data_low = (Ftdi.SET_BITS_LOW,
                           self.IDLE & ~(self.SDA_O_BIT | self.SCL_BIT),
                           self._direction)
     self._clock_low_data_high = (Ftdi.SET_BITS_LOW,
                                  self.IDLE & ~self.SCL_BIT,
                                  self._direction)
     self._read_bit = (Ftdi.READ_BITS_PVE_MSB, 0)
     self._read_byte = (Ftdi.READ_BYTES_PVE_MSB, 0, 0)
     self._write_byte = (Ftdi.WRITE_BYTES_NVE_MSB, 0, 0)
     self._nack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.HIGH)
     self._ack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.LOW)
     self._start = data_low * 4 + clock_low_data_low * 4
     self._stop = clock_low_data_low * 4 + data_low * 4 + self._idle * 4
     self._tristate = None
     self._tx_size = 1
     self._rx_size = 1
Example #7
0
 def __init__(self, trst=False, frequency=3.0E6, usb_read_timeout=5000, usb_write_timeout=5000, debug=False):
     """
     trst uses the nTRST optional JTAG line to hard-reset the TAP
       controller
     """
     self._ftdi = Ftdi()
     self._lock = Lock()
     self._ftdi.timeouts = (usb_read_timeout, usb_write_timeout)
     self._trst = trst
     self._frequency = frequency
     self._ftdi_opened = False
     self._immediate = bytes((Ftdi.SEND_IMMEDIATE,))
     self.direction = (JtagController.TCK_BIT |
                       JtagController.TDI_BIT |
                       JtagController.TMS_BIT |
                       (self._trst and JtagController.TRST_BIT or 0))
     # all JTAG outputs are low - Additionally, setting this upper
     # bits as outputs and then having a specific initial value
     # gets the PYNQ-Z1 board working
     self.direction |= 0x90
     self.initialout = 0xe0  
     #@@@#self.initialout = self.direction
     self._last = None  # Last deferred TDO bit
     self._write_buff = array('B')
     self._debug = debug
Example #8
0
 def createdevpinout(self,ftdidevicename,devtype="",devorder=-1):
  global PINOUT
  startpoint = len(Settings.Pinout)
  try:
   fi = Ftdi()
   fi = fi.create_from_url(ftdidevicename)
   gpionum = fi.port_width
   lismpsse = fi.has_mpsse
   lportindex = fi.port_index
   fi.close()
  except Exception as e:
   gpionum = 0
  if gpionum>0:
   for g in range(0,gpionum):
    pname = get_ftdi_pinnames(g,lportindex,lismpsse)
    if devorder>-1:
     try:
      pname[2] = pname[2].replace("SPI-","SPI"+str(devorder)+"-")
      pname[3] = pname[3].replace("I2C-","I2C"+str(devorder)+"-")
     except:
      pass
    pindet = {"ID": int(startpoint+g),
"BCM":int(startpoint+g),
"realpin":int(g),
"name":pname,
"canchange":1,
"altfunc": 0,
"startupstate":-1,
"actualstate":-1,
"ftdevice":ftdidevicename,
"ftdevtype":devtype
}
    Settings.Pinout.append(pindet)
    pindet = None
Example #9
0
def open_interface(tty, bitrate, logger=None):
    if logger:
        logger.debug("open_interface: {} {:d}".format(tty, bitrate))

    # Different procedures are required for PyFTDI and PySerial
    if len(tty) > 4 and tty[:4] == "ftdi":
        from pyftdi.ftdi import Ftdi
        import pyftdi.serialext

        for pid in FTDI_PRODUCT_IDS:
            try:
                Ftdi.add_custom_product(Ftdi.DEFAULT_VENDOR, pid)
            except ValueError:
                pass

        if logger:
            logger.info("Using pyftdi")

        Ftdi.show_devices()
        ser = pyftdi.serialext.serial_for_url(tty,
                                              baudrate=bitrate,
                                              timeout=DEFAULT_TIMEOUT_SECONDS)
        # XXX should raise exception for illegal caudrate
    else:
        import serial
        if logger:
            logger.debug("Using pyserial")
        try:
            ser = serial.Serial(tty, bitrate, timeout=DEFAULT_TIMEOUT_SECONDS)
        except serial.SerialException:
            raise

    return ser
Example #10
0
 def test(self):
     ftdi = Ftdi()
     ftdi.open_from_url(URL)
     for baudrate in self.BAUDRATES:
         actual, _, _ = ftdi._convert_baudrate(baudrate)
         ratio = baudrate / actual
         self.assertTrue(0.97 <= ratio <= 1.03, "Invalid baudrate")
Example #11
0
 def __init__(self):
     self._ftdi = Ftdi()
     self.log = getLogger('pyftdi.i2c')
     self._slaves = {}
     self._retry_count = self.RETRY_COUNT
     self._frequency = 0.0
     self._direction = self.SCL_BIT | self.SDA_O_BIT
     self._immediate = (Ftdi.SEND_IMMEDIATE, )
     self._idle = (Ftdi.SET_BITS_LOW, self.IDLE, self._direction)
     self._data_lo = (Ftdi.SET_BITS_LOW, self.IDLE & ~self.SDA_O_BIT,
                      self._direction)
     self._clk_lo_data_lo = (Ftdi.SET_BITS_LOW,
                             self.IDLE & ~(self.SDA_O_BIT | self.SCL_BIT),
                             self._direction)
     self._clk_lo_data_hi = (Ftdi.SET_BITS_LOW, self.IDLE & ~self.SCL_BIT,
                             self._direction)
     self._read_bit = (Ftdi.READ_BITS_PVE_MSB, 0)
     self._read_byte = (Ftdi.READ_BYTES_PVE_MSB, 0, 0)
     self._write_byte = (Ftdi.WRITE_BYTES_NVE_MSB, 0, 0)
     self._nack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.HIGH)
     self._ack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.LOW)
     self._start = None
     self._stop = None
     self._ck_delay = 1
     self._tristate = None
     self._tx_size = 1
     self._rx_size = 1
Example #12
0
    def __init__(self, deviceid):
        """

        :rtype: object
        """
        # self.input = queue.Queue(20)
        self.packetCallback = None
        self.errorCallback = None

        self._commandLock = Lock()
        self._packetReadEvent = Event()
        self._startedEvent = Event()
        self._stoppedEvent = Event()
        self._run = True
        self.device_id = deviceid
        self._ftdi = Ftdi()
        self.numScanners = 0
        self.numRelays = 0
        self.relaystatus = {}
        self.version = "0.00"
        self.model = "unknown"
        self._unlockTimeouts = {}

        self._parserState = ParserState.BEGIN
        self._firstChar = ' '
        self._body = bytearray()

        # self.ftdi.open(vendor=0x0403,product=0x6001, serial=self.device)
        self._ftdi.open_from_url(self.device_id)
        self._ftdi.set_baudrate(57600)

        self._backgroundThread = Thread(target=self.background)
        self._backgroundThread.start()
        self._otherThread = Thread(target=self.lock_watch_loop)
        self._otherThread.start()

        if not self._startedEvent.wait(3.0):
            raise RuntimeError("Unable to startup board!")
        else:
            logger.log(logging.DEBUG, "Started up, disabling echo")
            self.send_command('e', '0')

            def get_device_info(fc, b, me):
                if fc == 'I':
                    info = {i.split(':')[0]: i.split(':')[1] for i in b.split(',')}
                    self.model = info['m']
                    self.version = info['v']
                    self.numRelays = int(info['r'])
                    self.numScanners = int(info['s'])
                    for a in range(self.numRelays):
                        self._unlockTimeouts[a] = []
                        self.relaystatus[a] = False

            self.packetCallback = get_device_info
            logger.info("calling getting device info")
            self.send_command('i', '')
            logger.info("done interrogating")

            self.packetCallback = None
Example #13
0
    def __init__(self, name, serial=None, port='A', baudrate=115200):
        '''
            discover and initialize Tunnel_DAC hardware
            
            Input:
                serial - serial number of the FTDI converter
                channel - 2 character channel id the DAC is connected to;
                    the first byte identifies the channel (A..D for current devices)
                    the second byte identifies the bit within that channel (0..7)
                numdacs - number of DACs daisy-chained on that line
                delay - communications delay assumed between PC and the USB converter
        '''
        logging.info(__name__ + ': Initializing instrument Tunnel_DAC')
        Instrument.__init__(self, name, tags=['physical'])

        self._conn = Ftdi()
        # VIDs and PIDs of converters used
        vps = [
            (0x0403, 0x6011),  # FTDI UM4232H 4ch
            (0x0403, 0x6014)  # FTDI UM232H 1ch
        ]
        # explicitly clear device cache of UsbTools
        #UsbTools.USBDEVICES = []
        # find all devices and obtain serial numbers
        devs = self._conn.find_all(vps)
        # filter list by serial number if provided
        if (serial != None):
            devs = [dev for dev in devs if dev[2] == serial]
        if (len(devs) == 0):
            logging.error(__name__ + ': failed to find matching FTDI devices.')
        elif (len(devs) > 1):
            logging.error(
                __name__ +
                ': more than one converter found and no serial number given.')
            logging.info(__name__ + ': available devices are: %s.' %
                         str([dev[2] for dev in devs]))
        vid, pid, self._serial, ports, description = devs[0]
        self._ports = [chr(ord('A') + i) for i in range(ports)]

        # open device
        (self._port, bit) = self._parse_channel_string(port)
        self._conn.open(vid,
                        pid,
                        interface=ord(self._port) - ord('A') + 1,
                        serial=self._serial)
        logging.info(__name__ +
                     ': using converter with serial #%s' % self._serial)
        self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG)
        self._set_baudrate(baudrate)

        # provide user interface
        self.add_parameter('port',
                           type=types.StringType,
                           flags=Instrument.FLAG_GET)
        #self.add_parameter('aliases', type=types.DictType, flags=Instrument.FLAG_GETSET)
        self.add_function('digital_out')
        self.add_function('digital_stream')
        self.add_function('set_aliases')
        self.add_function('get_aliases')
Example #14
0
 def __init__(self, debug=False):
     self.blaster = Ftdi()
     self.virtual = True
     self.blaster.LATENCY_MIN = 1
     self.blaster.open(0x09FB, 0x6001)
     self.blaster.write_data_set_chunksize(1)
     self._last = None  # Last deferred TDO bit
     self.debug = debug
    def testShowDevicesExtractURLs(self):
        portList = StringIO()
        Ftdi.show_devices(out=portList)
        text = portList.getvalue()
        self.assertTrue(len(text) > 0)

        urls = []
        for someText in text.split():
            if re.match("ftdi://", someText, re.IGNORECASE):
                urls.append(someText)
    def availableFTDIURLs(self):
        portList = StringIO()
        Ftdi.show_devices(out=portList)
        everything = portList.getvalue()

        urls = []
        for someText in everything.split():
            if re.match("ftdi://", someText, re.IGNORECASE):
                urls.append(someText)

        return urls
Example #17
0
 def connect(self):
     if self.dev.is_kernel_driver_active(0):
         self.dev.detach_kernel_driver(0)
     
     self._claim_dev()
     
     self._ftdi = Ftdi()
     self._ftdi.open_from_device(self.dev)
     
     self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.RESET)
     self._ftdi.set_bitmode(0xFF, Ftdi.BitMode.SYNCFF)
Example #18
0
 def __init__(self, silent_clock=False, cs_count=4, turbo=True):
     self._ftdi = Ftdi()
     self._lock = Lock()
     self._gpio_port = None
     self._gpio_dir = 0
     self._gpio_low = 0
     self._wide_port = False
     self._cs_count = cs_count
     self._turbo = turbo
     self._immediate = bytes((Ftdi.SEND_IMMEDIATE, ))
     self._frequency = 0.0
     self._clock_phase = False
Example #19
0
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:
            #pylint: disable-msg=import-outside-toplevel
            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)
Example #20
0
 def test_simple_reset(self):
     """Demonstrate how to connect to an hotplugged FTDI device, i.e.
        an FTDI device that is connected after the initial attempt to
        enumerate it on the USB bus."""
     url = environ.get('FTDI_DEVICE', 'ftdi:///1')
     ftdi = Ftdi()
     ftdi.open_from_url(url)
     self.assertTrue(ftdi.is_connected, 'Unable to connect to FTDI')
     ftdi.close()
     self.assertFalse(ftdi.is_connected, 'Unable to close connection')
     ftdi.open_from_url(url)
     self.assertTrue(ftdi.is_connected, 'Unable to connect to FTDI')
     ftdi.reset(False)
Example #21
0
 def open_from_url(self, url, direction, **kwargs):
     """
     """
     for k in ('direction',):
         if k in kwargs:
             del kwargs[k]
     try:
         ftdi = Ftdi()
         ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
         self._ftdi = ftdi
     except IOError as e:
         raise GpioException('Unable to open USB port: %s' % str(e))
     self._direction = direction
Example #22
0
 def __init__(self, trst=False, frequency=3.0E6):
     """
     trst uses the nTRST optional JTAG line to hard-reset the TAP
       controller
     """
     self._ftdi = Ftdi()
     self._trst = trst
     self._frequency = frequency
     self.direction = (JtagController.TCK_BIT | JtagController.TDI_BIT
                       | JtagController.TMS_BIT |
                       (self._trst and JtagController.TRST_BIT or 0))
     self._last = None  # Last deferred TDO bit
     self._write_buff = Array('B')
Example #23
0
class SDWire(StorageBase):
    def __init__(self, serial=None):
        self.serial = serial
        self.ftdi = Ftdi()

        self.vendor_id = 0x04e8
        self.product_id = 0x6001

    def _open(self):
        self.ftdi.open(vendor=self.vendor_id,
                       product=self.product_id,
                       serial=self.serial)

    def _close(self):
        self.ftdi.close()

    def to_host(self):
        self._open()
        self.ftdi.set_bitmode(mode=Ftdi.BitMode(0x20), bitmask=0xf1)
        self._close()

    def to_board(self):
        self._open()
        self.ftdi.set_bitmode(mode=Ftdi.BitMode(0x20), bitmask=0xf0)
        self._close()
Example #24
0
 def open(self, vendor, product, interface, direction, **kwargs):
     """
     """
     for k in ('direction',):
         if k in kwargs:
             del kwargs[k]
     try:
         ftdi = Ftdi()
         ftdi.open_bitbang(vendor, product, interface, direction=direction,
                           **kwargs)
         self._ftdi = ftdi
     except IOError as e:
         raise GpioException('Unable to open USB port: %s' % str(e))
     self._direction = direction
Example #25
0
 def setUp(self):
     """Open a connection to the FTDI, defining which pins are configured as
        output and input"""
     # out_pins value of 0x00 means all inputs
     out_pins = 0x00
     try:
         ftdi = Ftdi()
         # If you REALLY muck things up, need to use this open_bitbang()
         # function directly and enter vendor and product ID:
         # ftdi.open_bitbang(vendor=0x0403, product=0x6011,
         #                   direction=out_pins)
         ftdi.open_bitbang_from_url(self.url, direction=out_pins)
         self.ftdi = ftdi
     except IOError as ex:
         raise IOError('Unable to open USB port: %s' % str(ex))
Example #26
0
def query_devices(ignored_devices):
    if ignored_devices is not None and not hasattr(ignored_devices, '__iter__'):
        raise ValueError("Invalid ignored devices variable")

    ignored_ids = list(map(lambda d: d.device_id, ignored_devices))
    def map_url(dev):
        usb: UsbDeviceDescriptor = dev[0]
        vid = usb.vid
        pid = usb.pid
        if vid == 0x0403:
            vid = "ftdi"
        if pid == 0x6001:
            pid = "232"
        interface = dev[1]
        return f"ftdi://{vid}:{pid}:{usb.sn}/{interface}"

    all_devices = list(map(map_url, Ftdi.list_devices()))

    def not_ignored(dev):
        return dev not in ignored_ids

    if ignored_devices is None:
        to_query = all_devices
    else:
        to_query = list(filter(not_ignored, all_devices))

    discovered_boards = []
    for t in to_query:
        try:
            qb = ReaderBoard(deviceid=t)
            discovered_boards.append(qb.__repr__())
            qb.shutdown()
        except:
            pass
    return discovered_boards
Example #27
0
 def _init_dmx(self):
     self.ftdi = Ftdi()
     try:
         self.ftdi.open(VENDOR, PRODUCT, 0)
         self.ftdi.set_baudrate(self.baud_rate)
         self.ftdi.set_line_property(self.data_bits,
                                     self.stop_bits,
                                     self.parity,
                                     break_=Ftdi.BREAK_OFF)
         self.ftdi.set_flowctrl(self.flow_ctrl)
         self.ftdi.purge_buffers()
         self.ftdi.set_rts(self.rts_state)
         self._is_open = True
     except USBError, e:
         print e
         self._is_open = False
Example #28
0
    def get_ports(cls, serial: str = None):
        found_devices = []

        if serial is not None:
            if not serial.endswith('(I2C)'):
                return found_devices
            serial = serial[:-5]
        try:
            found = Ftdi.find_all([(Ftdi.DEFAULT_VENDOR, 0x6014)],
                                  nocache=True)
        except USBError:
            return found_devices
        except ValueError:
            return found_devices

        for d in found:
            if serial is not None:
                if d[2] == serial:
                    found_devices.append(cls(d[2]))
                    return found_devices

            else:
                found_devices.append(cls(d[2]))

        return found_devices
Example #29
0
    def __init__(self, url):
        try:
            self.ftdi = Ftdi.create_from_url(url)
        except UsbToolsError:
            raise Error('no device found for URL %s' % url)

        self.i2c = I2cController()
        self.i2c.set_retry_count(1)
        self.i2c.configure(url)

        self.gpio = Device.GpioController(self.ftdi)
        port = self.i2c.get_port(0x74)

        self.buttons = []
        self.rails = []

        self.power = Device.I2cButton(port, "power", 0x7, 0x3, 4)
        self.buttons.append(self.power)

        self.reset = Device.I2cButton(port, "reset", 0x6, 0x2, 3)
        self.buttons.append(self.reset)

        self.recovery = Device.I2cButton(port, "recovery", 0x7, 0x3, 3)
        self.buttons.append(self.recovery)

        self.force = Device.GpioButton(self.gpio, 6, "force-off")
        self.buttons.append(self.force)

        self.eeprom = Device.Eeprom(self.ftdi)

        self.core = Device.PowerRail(port, "core", 0x7, 0x1, 6)
        self.rails.append(self.core)

        self.cpu = Device.PowerRail(port, "cpu", 0x7, 0x1, 7)
        self.rails.append(self.cpu)
Example #30
0
 def test_enumerate(self):
     """Check simple enumeration of two similar FTDI device."""
     ftdi = Ftdi()
     temp_stdout = StringIO()
     with redirect_stdout(temp_stdout):
         self.assertRaises(SystemExit, ftdi.open_from_url, 'ftdi:///?')
     lines = [l.strip() for l in temp_stdout.getvalue().split('\n')]
     lines.pop(0)  # "Available interfaces"
     while lines and not lines[-1]:
         lines.pop()
     self.assertEqual(len(lines), 10)
     for line in lines:
         self.assertTrue(line.startswith('ftdi://'))
         # skip description, i.e. consider URL only
         url = line.split(' ')[0]
         urlparts = urlsplit(url)
         self.assertEqual(urlparts.scheme, 'ftdi')
         parts = urlparts.netloc.split(':')
         if parts[1] == '4232':
             # def file contains no serial number, so expect bus:addr syntax
             self.assertEqual(len(parts), 4)
             self.assertRegex(parts[2], r'^\d$')
             self.assertRegex(parts[3], r'^\d$')
         else:
             # other devices are assigned a serial number
             self.assertEqual(len(parts), 3)
             self.assertTrue(parts[2].startswith('FT'))
         self.assertRegex(urlparts.path, r'^/\d$')
Example #31
0
def scan_devices(sn):
    ftdi = Ftdi()
    devices = [d[0] for d in ftdi.list_devices()]

    # If the caller gave us a serial or a regex, keep only matching devices
    if sn:
        devices = [d for d in devices if re.search(sn, d.sn)]

    # Sorty devices by their serials so that the presentation order does not
    # depend on the order in which the devices were connected or reset.
    devices = sorted(devices, key=lambda d: d.sn)

    # Construct the FtdiEeprom object for each matching device
    devices = [load_eeprom(d.vid, d.pid, d.sn) for d in devices]

    return devices
Example #32
0
 def __init__(self):
     self._ftdi = Ftdi()
     self.log = getLogger('pyftdi.i2c')
     self._slaves = {}
     self._retry_count = self.RETRY_COUNT
     self._frequency = 0.0
     self._direction = self.SCL_BIT | self.SDA_O_BIT
     self._immediate = (Ftdi.SEND_IMMEDIATE,)
     self._idle = (Ftdi.SET_BITS_LOW, self.IDLE, self._direction)
     self._data_lo = (Ftdi.SET_BITS_LOW,
                      self.IDLE & ~self.SDA_O_BIT, self._direction)
     self._clk_lo_data_lo = (Ftdi.SET_BITS_LOW,
                             self.IDLE & ~(self.SDA_O_BIT | self.SCL_BIT),
                             self._direction)
     self._clk_lo_data_hi = (Ftdi.SET_BITS_LOW,
                             self.IDLE & ~self.SCL_BIT,
                             self._direction)
     self._read_bit = (Ftdi.READ_BITS_PVE_MSB, 0)
     self._read_byte = (Ftdi.READ_BYTES_PVE_MSB, 0, 0)
     self._write_byte = (Ftdi.WRITE_BYTES_NVE_MSB, 0, 0)
     self._nack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.HIGH)
     self._ack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.LOW)
     self._start = None
     self._stop = None
     self._ck_delay = 1
     self._tristate = None
     self._tx_size = 1
     self._rx_size = 1
Example #33
0
	def __init__(self, idVendor, idProduct, interface):
		#all pins are in high impedance
		self.vendor = idVendor
		self.product = idProduct
		self.interface = interface

		self.f = Ftdi()
		self.f.open_bitbang(idVendor, idProduct, interface)
Example #34
0
File: gpio.py Project: eblot/pyftdi
    def configure(self, url, direction=0, **kwargs):
        """Open a new interface to the specified FTDI device in bitbang mode.

           :param str url: a FTDI URL selector
           :param int direction: a bitfield specifying the FTDI GPIO direction,
                where high level defines an output, and low level defines an
                input
        """
        for k in ('direction',):
            if k in kwargs:
                del kwargs[k]
        try:
            ftdi = Ftdi()
            ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
            self._ftdi = ftdi
        except IOError as ex:
            raise GpioException('Unable to open USB port: %s' % str(ex))
        self._direction = direction
Example #35
0
 def open(self):
     """Open the initialized serial port"""
     if self.port is None:
         raise SerialException("Port must be configured before use.")
     try:
         device = Ftdi.create_from_url(self.port)
     except (UsbToolsError, IOError) as ex:
         raise SerialException('Unable to open USB port %s: %s' %
                               (self.portstr, str(ex)))
     self.udev = device
     self._set_open_state(True)
     self._reconfigure_port()
Example #36
0
    def __init__(self, name, serial = None, port = 'A', baudrate = 115200):
        '''
            discover and initialize Tunnel_DAC hardware
            
            Input:
                serial - serial number of the FTDI converter
                channel - 2 character channel id the DAC is connected to;
                    the first byte identifies the channel (A..D for current devices)
                    the second byte identifies the bit within that channel (0..7)
                numdacs - number of DACs daisy-chained on that line
                delay - communications delay assumed between PC and the USB converter
        '''
        logging.info(__name__+ ': Initializing instrument Tunnel_DAC')
        Instrument.__init__(self, name, tags=['physical'])
        
        self._conn = Ftdi()
        # VIDs and PIDs of converters used
        vps = [
            (0x0403, 0x6011), # FTDI UM4232H 4ch
            (0x0403, 0x6014)  # FTDI UM232H 1ch
        ]
        # explicitly clear device cache of UsbTools
        #UsbTools.USBDEVICES = []
        # find all devices and obtain serial numbers
        devs = self._conn.find_all(vps)
        # filter list by serial number if provided
        if(serial != None):
            devs = [dev for dev in devs if dev[2] == serial]
        if(len(devs) == 0):
            logging.error(__name__ + ': failed to find matching FTDI devices.')
        elif(len(devs) > 1):
            logging.error(__name__ + ': more than one converter found and no serial number given.')
            logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs]))
        vid, pid, self._serial, ports, description = devs[0]
        self._ports = [chr(ord('A') + i) for i in range(ports)]

        # open device
        (self._port, bit) = self._parse_channel_string(port)
        self._conn.open(vid, pid, interface = ord(self._port) - ord('A') + 1, serial = self._serial)
        logging.info(__name__ + ': using converter with serial #%s'%self._serial)
        self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG)
        self._set_baudrate(baudrate)

        # provide user interface
        self.add_parameter('port', type=types.StringType, flags=Instrument.FLAG_GET)
        #self.add_parameter('aliases', type=types.DictType, flags=Instrument.FLAG_GETSET)
        self.add_function('digital_out')
        self.add_function('digital_stream')
        self.add_function('set_aliases')
        self.add_function('get_aliases')
Example #37
0
 def __init__(self, silent_clock=False, cs_count=4, turbo=True):
     self.log = getLogger('pyftdi.spi.ctrl')
     self._ftdi = Ftdi()
     self._lock = Lock()
     self._gpio_port = None
     self._gpio_dir = 0
     self._gpio_mask = 0
     self._gpio_low = 0
     self._wide_port = False
     self._cs_count = cs_count
     self._turbo = turbo
     self._immediate = bytes((Ftdi.SEND_IMMEDIATE,))
     self._frequency = 0.0
     self._clock_phase = False
Example #38
0
 def __init__(self, trst=False, frequency=3.0E6):
     """
     trst uses the nTRST optional JTAG line to hard-reset the TAP
       controller
     """
     self._ftdi = Ftdi()
     self._trst = trst
     self._frequency = frequency
     self.direction = JtagController.TCK_BIT | \
                      JtagController.TDI_BIT | \
                      JtagController.TMS_BIT | \
                      (self._trst and JtagController.TRST_BIT or 0)
     self._last = None # Last deferred TDO bit
     self._write_buff = Array('B')
Example #39
0
 def __init__(self, silent_clock=False, cs_count=4):
     self._ftdi = Ftdi()
     self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & ~(SpiController.CS_BIT - 1)
     self._ports = [None] * cs_count
     self._direction = self._cs_bits | SpiController.DO_BIT | SpiController.SCK_BIT
     self._cs_high = Array("B")
     if silent_clock:
         # Set SCLK as input to avoid emitting clock beats
         self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT])
     # /CS to SCLK delay, use 8 clock cycles as a HW tempo
     self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xFF])
     # Restore idle state
     self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction])
     self._immediate = Array("B", [Ftdi.SEND_IMMEDIATE])
     self._frequency = 0.0
Example #40
0
 def __init__(self, vendorid=VENDORID, productid=PRODUCTID,
                     interface=DEFAULTINTERFACE):
     '''
     Initialises FTDI device as Haptic Stimulator
     
     :param vendorid: int or hex NOT string
     gotten from lsusb for FTDI device
     :param productid: int or hex NOT string
     gotten from lsusb for FTDI device
     :param interface: int - for tested board is always 2'''
     self.ftdi = Ftdi()
     self.ftdi.open_bitbang(vendorid, productid, interface, 
                             direction = 0xFF)
                             # direction FF - all ports output
     self.lock = threading.RLock()
     self.ftdi.write_data([0]) # turn off all channels
Example #41
0
 def test_multiple_interface(self):
     # the following calls used to create issues (several interfaces from
     # the same device). The test expect an FTDI 2232H here
     ftdi1 = Ftdi()
     ftdi1.open(vendor=0x403, product=0x6014, interface=1)
     # ftdi2 = Ftdi()
     # ftdi2.open(vendor=0x403, product=0x6014, interface=2)
     import time
     for x in range(5):
         print "poll_modem_status: ", hex(ftdi1.poll_modem_status())
         # print "modem_status: ", ftdi1.modem_status()
         # print "If#2: ", ftdi2.modem_status()
         time.sleep(0.500)
     ftdi1.close()
Example #42
0
 def __init__(self, silent_clock=False, cs_count=4, turbo=True):
     self._ftdi = Ftdi()
     self._cs_bits = (((SpiController.CS_BIT << cs_count) - 1) &
                      ~(SpiController.CS_BIT - 1))
     self._ports = [None] * cs_count
     self._direction = (self._cs_bits |
                        SpiController.DO_BIT |
                        SpiController.SCK_BIT)
     self._turbo = turbo
     self._cs_high = Array('B')
     if self._turbo:
         if silent_clock:
             # Set SCLK as input to avoid emitting clock beats
             self._cs_high.extend((Ftdi.SET_BITS_LOW, self._cs_bits,
                                   self._direction & ~SpiController.SCK_BIT))
         # /CS to SCLK delay, use 8 clock cycles as a HW tempo
         self._cs_high.extend((Ftdi.WRITE_BITS_TMS_NVE, 8-1, 0xff))
     # Restore idle state
     self._cs_high.extend((Ftdi.SET_BITS_LOW, self._cs_bits,
                           self._direction))
     if not self._turbo:
         self._cs_high.append(Ftdi.SEND_IMMEDIATE)
     self._immediate = Array('B', (Ftdi.SEND_IMMEDIATE,))
     self._frequency = 0.0
Example #43
0
class I2cController:
    """I2c master.

       An I2c master should be instanciated only once for each FTDI port that
       supports MPSSE (one or two ports, depending on the FTDI device).

       Once configured, :py:func:`get_port` should be invoked to obtain an I2c
       port for each I2c slave to drive. I2cport should handle all I/O requests
       for its associated HW slave.

       It is not recommended to use I2cController :py:func:`read`,
       :py:func:`write` or :py:func:`exchange` directly.
    """

    LOW = 0x00
    HIGH = 0xff
    BIT0 = 0x01
    IDLE = HIGH
    SCL_BIT = 0x01
    SDA_O_BIT = 0x02
    SDA_I_BIT = 0x04
    PAYLOAD_MAX_LENGTH = 0x10000  # 16 bits max
    HIGHEST_I2C_ADDRESS = 0x78
    DEFAULT_BUS_FREQUENCY = 100000.0
    HIGH_BUS_FREQUENCY = 400000.0
    RETRY_COUNT = 3

    I2C_100K = I2CTimings(4.0E-6, 4.7E-6, 4.0E-6, 4.7E-6)
    I2C_400K = I2CTimings(0.6E-6, 0.6E-6, 0.6E-6, 1.3E-6)
    I2C_1M = I2CTimings(0.26E-6, 0.26E-6, 0.26E-6, 0.5E-6)

    def __init__(self):
        self._ftdi = Ftdi()
        self.log = getLogger('pyftdi.i2c')
        self._slaves = {}
        self._retry_count = self.RETRY_COUNT
        self._frequency = 0.0
        self._direction = self.SCL_BIT | self.SDA_O_BIT
        self._immediate = (Ftdi.SEND_IMMEDIATE,)
        self._idle = (Ftdi.SET_BITS_LOW, self.IDLE, self._direction)
        self._data_lo = (Ftdi.SET_BITS_LOW,
                         self.IDLE & ~self.SDA_O_BIT, self._direction)
        self._clk_lo_data_lo = (Ftdi.SET_BITS_LOW,
                                self.IDLE & ~(self.SDA_O_BIT | self.SCL_BIT),
                                self._direction)
        self._clk_lo_data_hi = (Ftdi.SET_BITS_LOW,
                                self.IDLE & ~self.SCL_BIT,
                                self._direction)
        self._read_bit = (Ftdi.READ_BITS_PVE_MSB, 0)
        self._read_byte = (Ftdi.READ_BYTES_PVE_MSB, 0, 0)
        self._write_byte = (Ftdi.WRITE_BYTES_NVE_MSB, 0, 0)
        self._nack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.HIGH)
        self._ack = (Ftdi.WRITE_BITS_NVE_MSB, 0, self.LOW)
        self._start = None
        self._stop = None
        self._ck_delay = 1
        self._tristate = None
        self._tx_size = 1
        self._rx_size = 1

    def _compute_delay_cycles(self, value):
        # approx ceiling without relying on math module
        # the bit delay is far from being precisely known anyway
        bit_delay = self._ftdi.mpsse_bit_delay
        return max(1, int((value + bit_delay) / bit_delay))

    def set_retry_count(self, count):
        """Change the default retry count when a communication error occurs,
           before bailing out.
           :param int count: count of retries
        """
        if not isinstance(count, int) or not 0 < count <= 16:
            raise ValueError('Invalid retry count')
        self._retry_count = count

    def configure(self, url, **kwargs):
        """Configure the FTDI interface as a I2c master.

           :param str url: FTDI URL string, such as 'ftdi://ftdi:232h/1'
           :param kwargs: options to configure the I2C bus

           Accepted options:

           * ``frequency`` the I2C bus frequency in Hz
        """
        for k in ('direction', 'initial'):
            if k in kwargs:
                del kwargs[k]
        if 'frequency' in kwargs:
            frequency = kwargs['frequency']
            del kwargs['frequency']
        else:
            frequency = self.DEFAULT_BUS_FREQUENCY
        # Fix frequency for 3-phase clock
        if frequency <= 100E3:
            timings = self.I2C_100K
        elif frequency <= 400E3:
            timings = self.I2C_100K
        else:
            timings = self.I2C_100K
        ck_hd_sta = self._compute_delay_cycles(timings.t_hd_sta)
        ck_su_sta = self._compute_delay_cycles(timings.t_su_sta)
        ck_su_sto = self._compute_delay_cycles(timings.t_su_sto)
        ck_buf = self._compute_delay_cycles(timings.t_buf)
        ck_idle = max(ck_su_sta, ck_buf)
        self._ck_delay = ck_buf
        self._start = (self._data_lo * ck_hd_sta +
                       self._clk_lo_data_lo * ck_hd_sta)
        self._stop = (self._clk_lo_data_lo * ck_hd_sta +
                      self._data_lo*ck_su_sto +
                      self._idle*ck_idle)
        frequency = (3.0*frequency)/2.0
        self._frequency = self._ftdi.open_mpsse_from_url(
            url, direction=self._direction, initial=self.IDLE,
            frequency=frequency, **kwargs)
        self._tx_size, self._rx_size = self._ftdi.fifo_sizes
        self._ftdi.enable_adaptive_clock(False)
        self._ftdi.enable_3phase_clock(True)
        try:
            self._ftdi.enable_drivezero_mode(self.SCL_BIT |
                                             self.SDA_O_BIT |
                                             self.SDA_I_BIT)
        except FtdiFeatureError:
            self._tristate = (Ftdi.SET_BITS_LOW, self.LOW, self.SCL_BIT)

    def terminate(self):
        """Close the FTDI interface.
        """
        if self._ftdi:
            self._ftdi.close()
            self._ftdi = None

    def get_port(self, address):
        """Obtain an I2cPort to drive an I2c slave.

           :param int address: the address on the I2C bus
           :return: an I2cPort instance
           :rtype: :py:class:`I2cPort`
        """
        if not self._ftdi:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if address not in self._slaves:
            self._slaves[address] = I2cPort(self, address)
        return self._slaves[address]

    @property
    def configured(self):
        """Test whether the device has been properly configured.

           :return: True if configured
        """
        return bool(self._ftdi) and bool(self._start)

    @classmethod
    def validate_address(cls, address):
        """Assert an I2C slave address is in the supported range.
           None is a special bypass address.

           :param address: the address on the I2C bus
           :type address: int or None
           :raise I2cIOError: if the I2C slave address is not supported
        """
        if address is None:
            return
        if address > cls.HIGHEST_I2C_ADDRESS:
            raise I2cIOError("No such I2c slave: 0x%02x" % address)

    @property
    def frequency_max(self):
        """Provides the maximum I2c clock frequency.
        """
        return self._ftdi.frequency_max

    @property
    def frequency(self):
        """Provides the current I2c clock frequency.

           :return: the I2C bus clock
           :rtype: float
        """
        return self._frequency

    def read(self, address, readlen=1, relax=True):
        """Read one or more bytes from a remote slave

           :param address: the address on the I2C bus, or None to discard start
           :type address: int or None
           :param int readlen: count of bytes to read out.
           :param bool relax: not used
           :return: read bytes
           :rtype: array
           :raise I2cIOError: if device is not configured or input parameters
                              are invalid

           Address is a logical slave address (0x7f max)

           Most I2C devices require a register address to read out
           check out the exchange() method.
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if address is None:
            i2caddress = None
        else:
            i2caddress = (address << 1) & self.HIGH
            i2caddress |= self.BIT0
        retries = self._retry_count
        do_epilog = True
        while True:
            try:
                self._do_prolog(i2caddress)
                data = self._do_read(readlen)
                do_epilog = relax
                return data
            except I2cNackError:
                retries -= 1
                if not retries:
                    raise
                self.log.warning('Retry read')
            finally:
                if do_epilog:
                    self._do_epilog()

    def write(self, address, out, relax=True):
        """Write one or more bytes to a remote slave

           :param address: the address on the I2C bus, or None to discard start
           :type address: int or None
           :param out: the byte buffer to send
           :type out: array or bytes or list(int)
           :param bool relax: whether to relax the bus (emit STOP) or not
           :raise I2cIOError: if device is not configured or input parameters
                              are invalid

           Address is a logical slave address (0x7f max)

           Most I2C devices require a register address to write into. It should
           be added as the first (byte)s of the output buffer.
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if address is None:
            i2caddress = None
        else:
            i2caddress = (address << 1) & self.HIGH
        retries = self._retry_count
        do_epilog = True
        while True:
            try:
                self._do_prolog(i2caddress)
                self._do_write(out)
                do_epilog = relax
                return
            except I2cNackError:
                retries -= 1
                if not retries:
                    raise
                self.log.warning('Retry write')
            finally:
                if do_epilog:
                    self._do_epilog()

    def exchange(self, address, out, readlen=0, relax=True):
        """Send a byte sequence to a remote slave followed with
           a read request of one or more bytes.

           This command is useful to tell the slave what data
           should be read out.

           :param address: the address on the I2C bus, or None to discard start
           :type address: int or None
           :param out: the byte buffer to send
           :type out: array or bytes or list(int)
           :param int readlen: count of bytes to read out.
           :param bool relax: whether to relax the bus (emit STOP) or not
           :return: read bytes
           :rtype: array
           :raise I2cIOError: if device is not configured or input parameters
                              are invalid

           Address is a logical slave address (0x7f max)
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if readlen < 1:
            raise I2cIOError('Nothing to read')
        if readlen > (I2cController.PAYLOAD_MAX_LENGTH/3-1):
            raise I2cIOError("Input payload is too large")
        if address is None:
            i2caddress = None
        else:
            i2caddress = (address << 1) & self.HIGH
        retries = self._retry_count
        do_epilog = True
        while True:
            try:
                self._do_prolog(i2caddress)
                self._do_write(out)
                self._do_prolog(i2caddress | self.BIT0)
                if readlen:
                    data = self._do_read(readlen)
                do_epilog = relax
                return data
            except I2cNackError:
                retries -= 1
                if not retries:
                    raise
                self.log.warning('Retry exchange')
            finally:
                if do_epilog:
                    self._do_epilog()

    def poll(self, address, write=False, relax=True):
        """Poll a remote slave, expect ACK or NACK.

           :param address: the address on the I2C bus, or None to discard start
           :type address: int or None
           :param bool write: poll in write mode (vs. read)
           :param bool relax: whether to relax the bus (emit STOP) or not
           :return: True if the slave acknowledged, False otherwise
           :rtype: bool
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if address is None:
            i2caddress = None
        else:
            i2caddress = (address << 1) & self.HIGH
            if not write:
                i2caddress |= self.BIT0
        do_epilog = True
        try:
            self._do_prolog(i2caddress)
            do_epilog = relax
            return True
        except I2cNackError:
            self.log.info('Not ready')
            return False
        finally:
            if do_epilog:
                self._do_epilog()

    def poll_cond(self, address, fmt, mask, value, count, relax=True):
        """Poll a remove slave, watching for condition to satisfy.
           On each poll cycle, a repeated start condition is emitted, without
           releasing the I2C bus, and an ACK is returned to the slave.

           If relax is set, this method releases the I2C bus however it leaves.

           :param address: the address on the I2C bus, or None to discard start
           :type address: int or None
           :param str fmt: struct format for poll register
           :param int mask: binary mask to apply on the condition register
                before testing for the value
           :param int value: value to test the masked condition register
                against. Condition is satisfied when register & mask == value
           :param int count: maximum poll count before raising a timeout
           :param bool relax: whether to relax the bus (emit STOP) or not
           :return: the polled register value, or None if poll failed
           :rtype: array or None
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self.validate_address(address)
        if address is None:
            i2caddress = None
        else:
            i2caddress = (address << 1) & self.HIGH
            i2caddress |= self.BIT0
        do_epilog = True
        try:
            retry = 0
            while retry < count:
                retry += 1
                size = scalc(fmt)
                self._do_prolog(i2caddress)
                data = self._do_read(size)
                self.log.debug("Poll data: %s", hexlify(data).decode())
                cond, = sunpack(fmt, data)
                if (cond & mask) == value:
                    self.log.debug('Poll condition matched')
                    break
                else:
                    data = None
                    self.log.debug('Poll condition not fulfilled: %x/%x',
                                   cond & mask, value)
            do_epilog = relax
            if not data:
                self.log.warning('Poll condition failed')
            return data
        except I2cNackError:
            self.log.info('Not ready')
            return None
        finally:
            if do_epilog:
                self._do_epilog()

    def flush(self):
        """Flush the HW FIFOs
        """
        if not self.configured:
            raise I2cIOError("FTDI controller not initialized")
        self._ftdi.write_data(self._immediate)
        self._ftdi.purge_buffers()

    def _do_prolog(self, i2caddress):
        if i2caddress is None:
            return
        self.log.debug('   prolog 0x%x', i2caddress >> 1)
        cmd = array('B', self._idle)
        cmd.extend(self._start)
        cmd.extend(self._write_byte)
        cmd.append(i2caddress)
        if self._tristate:
            cmd.extend(self._tristate)
            cmd.extend(self._read_bit)
            cmd.extend(self._clk_lo_data_hi)
        else:
            cmd.extend(self._clk_lo_data_hi)
            cmd.extend(self._read_bit)
        cmd.extend(self._immediate)
        self._ftdi.write_data(cmd)
        ack = self._ftdi.read_data_bytes(1, 4)
        if not ack:
            raise I2cIOError('No answer from FTDI')
        if ack[0] & self.BIT0:
            self.log.warning('NACK')
            raise I2cNackError('NACK from slave')

    def _do_epilog(self):
        self.log.debug('   epilog')
        cmd = array('B', self._stop)
        self._ftdi.write_data(cmd)
        # be sure to purge the MPSSE reply
        self._ftdi.read_data_bytes(1, 1)

    def _do_read(self, readlen):
        self.log.debug('- read %d byte(s)', readlen)
        if not readlen:
            # force a real read request on device, but discard any result
            cmd = array('B')
            cmd.extend(self._immediate)
            self._ftdi.write_data(cmd)
            self._ftdi.read_data_bytes(0, 4)
            return array('B')
        if self._tristate:
            read_byte = self._tristate + \
                        self._read_byte + \
                        self._clk_lo_data_hi
            read_not_last = \
                read_byte + self._ack + self._clk_lo_data_lo * self._ck_delay
            read_last = \
                read_byte + self._nack + self._clk_lo_data_hi * self._ck_delay
        else:
            read_not_last = \
                self._read_byte + self._ack + \
                self._clk_lo_data_hi * self._ck_delay
            read_last = \
                self._read_byte + self._nack + \
                self._clk_lo_data_hi * self._ck_delay
        # maximum RX size to fit in FTDI FIFO, minus 2 status bytes
        chunk_size = self._rx_size-2
        cmd_size = len(read_last)
        # limit RX chunk size to the count of I2C packable commands in the FTDI
        # TX FIFO (minus one byte for the last 'send immediate' command)
        tx_count = (self._tx_size-1) // cmd_size
        chunk_size = min(tx_count, chunk_size)
        chunks = []
        cmd = None
        rem = readlen
        while rem:
            if rem > chunk_size:
                if not cmd:
                    cmd = array('B')
                    cmd.extend(read_not_last * chunk_size)
                    size = chunk_size
            else:
                cmd = array('B')
                cmd.extend(read_not_last * (rem-1))
                cmd.extend(read_last)
                cmd.extend(self._immediate)
                size = rem
            self._ftdi.write_data(cmd)
            buf = self._ftdi.read_data_bytes(size, 4)
            self.log.debug('- read %d byte(s): %s',
                           len(buf), hexlify(buf).decode())
            chunks.append(buf)
            rem -= size
        return array('B', b''.join(chunks))

    def _do_write(self, out):
        if not isinstance(out, array):
            out = array('B', out)
        if not out:
            return
        self.log.debug('- write %d byte(s): %s',
                       len(out), hexlify(out).decode())
        for byte in out:
            cmd = array('B', self._write_byte)
            cmd.append(byte)
            if self._tristate:
                cmd.extend(self._tristate)
                cmd.extend(self._read_bit)
                cmd.extend(self._clk_lo_data_hi)
            else:
                cmd.extend(self._clk_lo_data_hi)
                cmd.extend(self._read_bit)
            cmd.extend(self._immediate)
            self._ftdi.write_data(cmd)
            ack = self._ftdi.read_data_bytes(1, 4)
            if not ack:
                msg = 'No answer from FTDI'
                self.log.critical(msg)
                raise I2cIOError(msg)
            if ack[0] & self.BIT0:
                msg = 'NACK from slave'
                self.log.warning(msg)
                raise I2cNackError(msg)
Example #44
0
class Tunnel_DAC(Instrument):

    def __init__(self, name, serial = None, channel = 'A0', numdacs=3, delay = 1e-3):
        '''
            discover and initialize Tunnel_DAC hardware
            
            Input:
                serial - serial number of the FTDI converter
                channel - 2 character channel id the DAC is connected to;
                    the first byte identifies the channel (A..D for current devices)
                    the second byte identifies the bit within that channel (0..7)
                numdacs - number of DACs daisy-chained on that line
                delay - communications delay assumed between PC and the USB converter
        '''
        logging.info(__name__+ ': Initializing instrument Tunnel_DAC')
        Instrument.__init__(self, name, tags=['physical'])
        
        self._conn = Ftdi()
        # VIDs and PIDs of converters used
        vps = [
            (0x0403, 0x6011), # FTDI UM4232H 4ch
            (0x0403, 0x6014)  # FTDI UM232H 1ch
        ]
        # explicitly clear device cache of UsbTools
        #UsbTools.USBDEVICES = []
        # find all devices and obtain serial numbers
        devs = self._conn.find_all(vps)
        # filter list by serial number if provided
        if(serial != None):
            devs = [dev for dev in devs if dev[2] == serial]
        if(len(devs) == 0):
            logging.error(__name__ + ': failed to find matching FTDI devices.')
        elif(len(devs) > 1):
            logging.error(__name__ + ': more than one converter found and no serial number given.')
            logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs]))
        vid, pid, self._serial, channels, description = devs[0]
        # parse channel string
        if(len(channel) != 2):
            logging.error(__name__ + ': channel identifier must be a string of length 2. ex. A0, D5.')
        self._channel = 1 + ord(channel[0]) - ord('A')
        self._bit = ord(channel[1]) - ord('0')
        if((self._channel < 1) or (self._channel > channels)):
            logging.error(__name__ + ': channel %c is not supported by this device.'%(chr(ord('A')+self._channel-1)))
        if((self._bit < 0) or (self._bit > 7)):
            logging.error(__name__ + ': subchannel must be between 0 and 7, not %d.'%self._bit)

        # open device
        self._conn.open(vid, pid, interface = self._channel, serial = self._serial)
        logging.info(__name__ + ': using converter with serial #%s'%self._serial)
        self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG)
        # 80k generates bit durations of 12.5us, 80 is magic :(
        # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices
        # original matlab code uses 19kS/s
        self._conn.set_baudrate(19000/80)

        # house keeping        
        self._numdacs = numdacs
        self._sleeptime = (10. + 16.*self._numdacs)*12.5e-6 + delay # 1st term from hardware parameters, 2nd term from USB  
        self._minval = -5000.
        self._maxval = 5000.
        self._resolution = 16 # DAC resolution in bits
        self._voltages = [0.]*numdacs
        
        self.add_parameter('voltage', type=types.FloatType, flags=Instrument.FLAG_SET, channels=(1, self._numdacs),
                           minval = self._minval, maxval = self._maxval, units='mV', format = '%.02f') # tags=['sweep']
        self.add_function('set_voltages')
        self.add_function('commit')


    def _encode(self, data, channel = 0, bits_per_item = 16, big_endian = True):
        '''
            convert binary data into line symbols
            
            the tunnel electronic DAC logic box triggers on rising 
            signal edges and samples data after 18us. we use a line
            code with three bits of duration 12us, where a logical 1
            is encoded as B"110" and a logical 0 is encoded as B"100".
            
            the line data is returned as a byte string with three bytes/symbol.
            
            Input:
                data - a vector of data entities (usually a string or list of integers)
                channel - a number in [0, 7] specifying the output bit on the USB-to-UART chip
                bits_per_item - number of bits to extract from each element of the data vector
        '''
        # build line code for the requested channel
        line_1 = chr(1<<channel)
        line_0 = chr(0)
        line_code = [''.join([line_0, line_1, line_1]), ''.join([line_0, line_1, line_0])]
        # do actual encoding
        result = []
        result.append(10*line_0)
        for item in data:
            for bit in (range(bits_per_item-1, -1, -1) if big_endian else range(0, bits_per_item)):
                result.append(line_code[1 if(item & (1<<bit)) else 0])
        result.append(10*line_0)
        return ''.join(result)


    def commit(self):
        '''
            send updated parameter values to the physical DACs via USB
        '''
        # normalize, scale, clip voltages
        voltages = [-1+2*(x-self._minval)/(self._maxval-self._minval) for x in self._voltages]
        voltages = [max(-2**(self._resolution-1), min(2**(self._resolution-1)-1, int(2**(self._resolution-1)*x))) for x in voltages]
        # encode and send
        data = self._encode(reversed(voltages), self._bit, self._resolution)
        self._conn.write_data(data)
        # wait for the FTDI fifo to clock the data to the DACs
        sleep(self._sleeptime)


    def do_set_voltage(self, value, channel):
        '''
            immediately update voltage on channel ch
            parameter checking is done by qtlab
        '''
        self._voltages[channel-1] = value
        self.commit()


    def set_voltages(self, valuedict):
        '''
            update voltages on several channels simultaneously
            todo: update instrument panel display
        '''
        for channel, value in valuedict.iteritems():
            # bounds checking & clipping
            if((channel < 1) or (channel > self._numdacs)):
                logging.error(__name__ + ': channel %d out of range.'%channel)
                continue
            value = float(value)
            if((value < self._minval) or (value >= self._maxval)):
                logging.error(__name__ + ': value %f out of range. clipping.'%value)
                value = max(self._minval, min(self._maxval, value)) # does not handle maxval correctly
            self._voltages[channel-1] = value
        self.commit()
Example #45
0
File: jtag.py Project: eblot/pyftdi
class JtagController(object):
    """JTAG master of an FTDI device"""

    TCK_BIT = 0x01  # FTDI output
    TDI_BIT = 0x02  # FTDI output
    TDO_BIT = 0x04  # FTDI input
    TMS_BIT = 0x08  # FTDI output
    TRST_BIT = 0x10  # FTDI output, not available on 2232 JTAG debugger
    JTAG_MASK = 0x1F
    FTDI_PIPE_LEN = 512

    # Private API
    def __init__(self, trst=False, frequency=3.0e6):
        """
        trst uses the nTRST optional JTAG line to hard-reset the TAP
          controller
        """
        self._ftdi = Ftdi()
        self._trst = trst
        self._frequency = frequency
        self.direction = (
            JtagController.TCK_BIT
            | JtagController.TDI_BIT
            | JtagController.TMS_BIT
            | (self._trst and JtagController.TRST_BIT or 0)
        )
        self._last = None  # Last deferred TDO bit
        self._write_buff = Array("B")

    def __del__(self):
        self.close()

    # Public API
    def configure(self, vendor, product, interface):
        """Configure the FTDI interface as a JTAG controller"""
        self._ftdi.open_mpsse(vendor, product, interface, direction=self.direction, frequency=self._frequency)
        # FTDI requires to initialize all GPIOs before MPSSE kicks in
        cmd = Array("B", (Ftdi.SET_BITS_LOW, 0x0, self.direction))
        self._ftdi.write_data(cmd)

    def close(self):
        if self._ftdi:
            self._ftdi.close()
            self._ftdi = None

    def purge(self):
        self._ftdi.purge_buffers()

    def reset(self, sync=False):
        """Reset the attached TAP controller.
           sync sends the command immediately (no caching)
        """
        # we can either send a TRST HW signal or perform 5 cycles with TMS=1
        # to move the remote TAP controller back to 'test_logic_reset' state
        # do both for now
        if not self._ftdi:
            raise JtagError("FTDI controller terminated")
        if self._trst:
            # nTRST
            value = 0
            cmd = Array("B", (Ftdi.SET_BITS_LOW, value, self.direction))
            self._ftdi.write_data(cmd)
            time.sleep(0.1)
            # nTRST should be left to the high state
            value = JtagController.TRST_BIT
            cmd = Array("B", (Ftdi.SET_BITS_LOW, value, self.direction))
            self._ftdi.write_data(cmd)
            time.sleep(0.1)
        # TAP reset (even with HW reset, could be removed though)
        self.write_tms(BitSequence("11111"))
        if sync:
            self.sync()

    def sync(self):
        if not self._ftdi:
            raise JtagError("FTDI controller terminated")
        if self._write_buff:
            self._ftdi.write_data(self._write_buff)
            self._write_buff = Array("B")

    def write_tms(self, tms):
        """Change the TAP controller state"""
        if not isinstance(tms, BitSequence):
            raise JtagError("Expect a BitSequence")
        length = len(tms)
        if not (0 < length < 8):
            raise JtagError("Invalid TMS length")
        out = BitSequence(tms, length=8)
        # apply the last TDO bit
        if self._last is not None:
            out[7] = self._last
        # print_("TMS", tms, (self._last is not None) and 'w/ Last' or '')
        # reset last bit
        self._last = None
        cmd = Array("B", (Ftdi.WRITE_BITS_TMS_NVE, length - 1, out.tobyte()))
        self._stack_cmd(cmd)
        self.sync()

    def read(self, length):
        """Read out a sequence of bits from TDO"""
        byte_count = length // 8
        bit_count = length - 8 * byte_count
        bs = BitSequence()
        if byte_count:
            bytes_ = self._read_bytes(byte_count)
            bs.append(bytes_)
        if bit_count:
            bits = self._read_bits(bit_count)
            bs.append(bits)
        return bs

    def write(self, out, use_last=True):
        """Write a sequence of bits to TDI"""
        if isinstance(out, str):
            if len(out) > 1:
                self._write_bytes_raw(out[:-1])
                out = out[-1]
            out = BitSequence(bytes_=out)
        elif not isinstance(out, BitSequence):
            out = BitSequence(out)
        if use_last:
            (out, self._last) = (out[:-1], bool(out[-1]))
        byte_count = len(out) // 8
        pos = 8 * byte_count
        bit_count = len(out) - pos
        if byte_count:
            self._write_bytes(out[:pos])
        if bit_count:
            self._write_bits(out[pos:])

    def shift_register(self, out, use_last=False):
        """Shift a BitSequence into the current register and retrieve the
           register output"""
        if not isinstance(out, BitSequence):
            return JtagError("Expect a BitSequence")
        length = len(out)
        if use_last:
            (out, self._last) = (out[:-1], int(out[-1]))
        byte_count = len(out) // 8
        pos = 8 * byte_count
        bit_count = len(out) - pos
        if not byte_count and not bit_count:
            raise JtagError("Nothing to shift")
        if byte_count:
            blen = byte_count - 1
            # print_("RW OUT %s" % out[:pos])
            cmd = Array("B", (Ftdi.RW_BYTES_PVE_NVE_LSB, blen, (blen >> 8) & 0xFF))
            cmd.extend(out[:pos].tobytes(msby=True))
            self._stack_cmd(cmd)
            # print_("push %d bytes" % byte_count)
        if bit_count:
            # print_("RW OUT %s" % out[pos:])
            cmd = Array("B", (Ftdi.RW_BITS_PVE_NVE_LSB, bit_count - 1))
            cmd.append(out[pos:].tobyte())
            self._stack_cmd(cmd)
            # print_("push %d bits" % bit_count)
        self.sync()
        bs = BitSequence()
        byte_count = length // 8
        pos = 8 * byte_count
        bit_count = length - pos
        if byte_count:
            data = self._ftdi.read_data_bytes(byte_count, 4)
            if not data:
                raise JtagError("Unable to read data from FTDI")
            byteseq = BitSequence(bytes_=data, length=8 * byte_count)
            # print_("RW IN %s" % byteseq)
            bs.append(byteseq)
            # print_("pop %d bytes" % byte_count)
        if bit_count:
            data = self._ftdi.read_data_bytes(1, 4)
            if not data:
                raise JtagError("Unable to read data from FTDI")
            byte = data[0]
            # need to shift bits as they are shifted in from the MSB in FTDI
            byte >>= 8 - bit_count
            bitseq = BitSequence(byte, length=bit_count)
            bs.append(bitseq)
            # print_("pop %d bits" % bit_count)
        if len(bs) != length:
            raise ValueError("Internal error")
        return bs

    def _stack_cmd(self, cmd):
        if not isinstance(cmd, Array):
            raise TypeError("Expect a byte array")
        if not self._ftdi:
            raise JtagError("FTDI controller terminated")
        # Currrent buffer + new command + send_immediate
        if (len(self._write_buff) + len(cmd) + 1) >= JtagController.FTDI_PIPE_LEN:
            self.sync()
        self._write_buff.extend(cmd)

    def _read_bits(self, length):
        """Read out bits from TDO"""
        if length > 8:
            raise JtagError("Cannot fit into FTDI fifo")
        cmd = Array("B", (Ftdi.READ_BITS_NVE_LSB, length - 1))
        self._stack_cmd(cmd)
        self.sync()
        data = self._ftdi.read_data_bytes(1, 4)
        # need to shift bits as they are shifted in from the MSB in FTDI
        byte = data[0] >> 8 - length
        bs = BitSequence(byte, length=length)
        # print_("READ BITS %s" % bs)
        return bs

    def _write_bits(self, out):
        """Output bits on TDI"""
        length = len(out)
        byte = out.tobyte()
        # print_("WRITE BITS %s" % out)
        cmd = Array("B", (Ftdi.WRITE_BITS_NVE_LSB, length - 1, byte))
        self._stack_cmd(cmd)

    def _read_bytes(self, length):
        """Read out bytes from TDO"""
        if length > JtagController.FTDI_PIPE_LEN:
            raise JtagError("Cannot fit into FTDI fifo")
        alen = length - 1
        cmd = Array("B", (Ftdi.READ_BYTES_NVE_LSB, alen & 0xFF, (alen >> 8) & 0xFF))
        self._stack_cmd(cmd)
        self.sync()
        data = self._ftdi.read_data_bytes(length, 4)
        bs = BitSequence(bytes_=data, length=8 * length)
        # print_("READ BYTES %s" % bs)
        return bs

    def _write_bytes(self, out):
        """Output bytes on TDI"""
        bytes_ = out.tobytes(msby=True)  # don't ask...
        olen = len(bytes_) - 1
        # print_("WRITE BYTES %s" % out)
        cmd = Array("B", (Ftdi.WRITE_BYTES_NVE_LSB, olen & 0xFF, (olen >> 8) & 0xFF))
        cmd.extend(bytes_)
        self._stack_cmd(cmd)

    def _write_bytes_raw(self, out):
        """Output bytes on TDI"""
        olen = len(out) - 1
        cmd = Array("B", (Ftdi.WRITE_BYTES_NVE_LSB, olen & 0xFF, (olen >> 8) & 0xFF))
        cmd.extend(out)
        self._stack_cmd(cmd)
Example #46
0
class BitBangController(object):
	

	PROGRAM_PIN 		=	0x20
	SOFT_RESET_PIN		=	0x40

	def __init__(self, idVendor, idProduct, interface):
		#all pins are in high impedance
		self.vendor = idVendor
		self.product = idProduct
		self.interface = interface

		self.f = Ftdi()
		self.f.open_bitbang(idVendor, idProduct, interface)


	def hiz(self):
		print "changing pins to high impedance"

	def is_in_bitbang(self):
		return self.f.bitbang_enabled

	def read_pins(self):
		return self.f.read_pins()

	def read_program_pin(self):
		return (self.PROGRAM_PIN & self.f.read_pins() > 0)
	
	def soft_reset_high(self):
		pins = self.f.read_pins()
		pins |= self.SOFT_RESET_PIN
		prog_cmd = Array('B', [0x01, pins])
		self.f.write_data(prog_cmd)
	
	def soft_reset_low(self):
		pins = self.f.read_pins()
		pins &= ~(self.SOFT_RESET_PIN)
		prog_cmd = Array('B', [0x00, pins])
		self.f.write_data(prog_cmd)

	def program_high(self):
		pins = self.f.read_pins()
		pins |= self.PROGRAM_PIN
		prog_cmd = Array('B', [0x01, pins])
		self.f.write_data(prog_cmd)

	def program_low(self):
		pins = self.f.read_pins()
		pins &= ~(self.PROGRAM_PIN)
		prog_cmd = Array('B', [0x00, pins])
		self.f.write_data(prog_cmd)
	
	def read_soft_reset_pin(self):
		return (self.SOFT_RESET_PIN & self.f.read_pins() > 0)

	def set_soft_reset_to_output(self):
		pin_dir = self.SOFT_RESET_PIN
		self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir)
	
	def set_program_to_output(self):
		pin_dir = self.PROGRAM_PIN
		self.f.open_bitbang(self.vendor, self.product, self.interface, direction = pin_dir)
		
	def set_pins_to_input(self):
		self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0x00)


	def set_pins_to_output(self):
		self.f.open_bitbang(self.vendor, self.product, self.interface, direction = 0xFF)


	def pins_on(self):
		prog_cmd = Array('B', [0x01, 0xFF]) 
		self.f.write_data(prog_cmd)

	def pins_off(self):
		prog_cmd = Array('B', [0x01, 0x00]) 
		self.f.write_data(prog_cmd)
Example #47
0
class FifoController (object):


	SYNC_FIFO_INTERFACE		=	1
	SYNC_FIFO_INDEX			=	0

	
	def __init__(self, idVendor, idProduct):
		self.vendor = idVendor
		self.product = idProduct
		self.f = Ftdi()

	def set_sync_fifo(self, frequency=30.0E6, latency=2):
		"""Configure the interface for synchronous FIFO mode"""
		# Open an FTDI interface
#		self.f.open(self.vendor, self.product, self.SYNC_FIFO_INTERFACE, self.SYNC_FIFO_INDEX, None, None)
		self.f.open(self.vendor, self.product, 0)
	# Drain input buffer
		self.f.purge_buffers()

		# Reset

		# Enable MPSSE mode
		self.f.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF)
		# Configure clock

		frequency = self.f._set_frequency(frequency)
		# Set latency timer
		self.f.set_latency_timer(latency)
		# Set chunk size
		self.f.write_data_set_chunksize(0x10000)
		self.f.read_data_set_chunksize(0x10000)
		
		self.f.set_flowctrl('hw')
		# Configure I/O
#		self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00]))
		# Disable loopback
#		self.write_data(Array('B', [Ftdi.LOOPBACK_END]))
#		self.validate_mpsse()
		# Drain input buffer
		self.f.purge_buffers()
		# Return the actual frequency
		return frequency

	def set_async_fifo(self, frequency=6.0E6, latency=2):
		"""Configure the interface for synchronous FIFO mode"""
		# Open an FTDI interface
		self.f.open(self.vendor, self.product, self.SYNC_FIFO_INTERFACE, self.SYNC_FIFO_INDEX, None, None)
		# Set latency timer
		self.f.set_latency_timer(latency)
		# Set chunk size
		self.f.write_data_set_chunksize(512)
		self.f.read_data_set_chunksize(512)
		# Drain input buffer
		self.f.purge_buffers()
		# Enable MPSSE mode
		self.f.set_bitmode(0x00, Ftdi.BITMODE_BITBANG)
		# Configure clock
		frequency = self.f._set_frequency(frequency)
		# Configure I/O
#		self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00]))
		# Disable loopback
#		self.write_data(Array('B', [Ftdi.LOOPBACK_END]))
#		self.validate_mpsse()
		# Drain input buffer
		self.f.purge_buffers()
		# Return the actual frequency
		return frequency
Example #48
0
    def __init__(self, name, serial = None, channel = 'A0', numdacs=3, delay = 1e-3):
        '''
            discover and initialize Tunnel_DAC hardware
            
            Input:
                serial - serial number of the FTDI converter
                channel - 2 character channel id the DAC is connected to;
                    the first byte identifies the channel (A..D for current devices)
                    the second byte identifies the bit within that channel (0..7)
                numdacs - number of DACs daisy-chained on that line
                delay - communications delay assumed between PC and the USB converter
        '''
        logging.info(__name__+ ': Initializing instrument Tunnel_DAC')
        Instrument.__init__(self, name, tags=['physical'])
        
        self._conn = Ftdi()
        # VIDs and PIDs of converters used
        vps = [
            (0x0403, 0x6011), # FTDI UM4232H 4ch
            (0x0403, 0x6014)  # FTDI UM232H 1ch
        ]
        # explicitly clear device cache of UsbTools
        #UsbTools.USBDEVICES = []
        # find all devices and obtain serial numbers
        devs = self._conn.find_all(vps)
        # filter list by serial number if provided
        if(serial != None):
            devs = [dev for dev in devs if dev[2] == serial]
        if(len(devs) == 0):
            logging.error(__name__ + ': failed to find matching FTDI devices.')
        elif(len(devs) > 1):
            logging.error(__name__ + ': more than one converter found and no serial number given.')
            logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs]))
        vid, pid, self._serial, channels, description = devs[0]
        # parse channel string
        if(len(channel) != 2):
            logging.error(__name__ + ': channel identifier must be a string of length 2. ex. A0, D5.')
        self._channel = 1 + ord(channel[0]) - ord('A')
        self._bit = ord(channel[1]) - ord('0')
        if((self._channel < 1) or (self._channel > channels)):
            logging.error(__name__ + ': channel %c is not supported by this device.'%(chr(ord('A')+self._channel-1)))
        if((self._bit < 0) or (self._bit > 7)):
            logging.error(__name__ + ': subchannel must be between 0 and 7, not %d.'%self._bit)

        # open device
        self._conn.open(vid, pid, interface = self._channel, serial = self._serial)
        logging.info(__name__ + ': using converter with serial #%s'%self._serial)
        self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG)
        # 80k generates bit durations of 12.5us, 80 is magic :(
        # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices
        # original matlab code uses 19kS/s
        self._conn.set_baudrate(19000/80)

        # house keeping        
        self._numdacs = numdacs
        self._sleeptime = (10. + 16.*self._numdacs)*12.5e-6 + delay # 1st term from hardware parameters, 2nd term from USB  
        self._minval = -5000.
        self._maxval = 5000.
        self._resolution = 16 # DAC resolution in bits
        self._voltages = [0.]*numdacs
        
        self.add_parameter('voltage', type=types.FloatType, flags=Instrument.FLAG_SET, channels=(1, self._numdacs),
                           minval = self._minval, maxval = self._maxval, units='mV', format = '%.02f') # tags=['sweep']
        self.add_function('set_voltages')
        self.add_function('commit')
Example #49
0
#!/usr/bin/env python

import sys
from array import array

# this library is jacked up, should not have to do this
# I'll probably fork/rewrite it, saving the bits that work
# for now it is quick to start
from pyftdi.ftdi import Ftdi


f = Ftdi()

# reset the FTDI chip
# HA! this can interrupt a continous clock forever mode
# to do something new

f.open_mpsse(0x403, 0x6014)
f.usb_dev.reset()
f.close()
print "reset!"

# here's the normal open
f.open_mpsse(0x403, 0x6014)

if len(sys.argv) > 1:
  freq = int(sys.argv[1])
else:
  freq = 1000 # or whatever

print "set freq: %d" % (freq,)
Example #50
0
	def __init__(self, idVendor, idProduct):
		self.vendor = idVendor
		self.product = idProduct
		self.dev = Ftdi()
		self.open_dev()
Example #51
0
class SpiController(object):
    """SPI master.

        :param silent_clock: should be set to avoid clocking out SCLK when all
                             /CS signals are released. This clock beat is used
                             to enforce a delay between /CS signal activation.

                             When weird SPI devices are used, SCLK beating may
                             cause trouble. In this case, silent_clock should
                             be set but beware that SCLK line should be fitted
                             with a pull-down resistor, as SCLK is high-Z
                             during this short period of time.
        :param cs_count: is the number of /CS lines (one per device to drive on
                         the SPI bus)
    """

    SCK_BIT = 0x01
    DO_BIT = 0x02
    DI_BIT = 0x04
    CS_BIT = 0x08
    PAYLOAD_MAX_LENGTH = 0x10000  # 16 bits max

    def __init__(self, silent_clock=False, cs_count=4):
        self._ftdi = Ftdi()
        self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & ~(SpiController.CS_BIT - 1)
        self._ports = [None] * cs_count
        self._direction = self._cs_bits | SpiController.DO_BIT | SpiController.SCK_BIT
        self._cs_high = Array("B")
        if silent_clock:
            # Set SCLK as input to avoid emitting clock beats
            self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT])
        # /CS to SCLK delay, use 8 clock cycles as a HW tempo
        self._cs_high.extend([Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xFF])
        # Restore idle state
        self._cs_high.extend([Ftdi.SET_BITS_LOW, self._cs_bits, self._direction])
        self._immediate = Array("B", [Ftdi.SEND_IMMEDIATE])
        self._frequency = 0.0

    def configure(self, vendor, product, interface, frequency=6.0e6):
        """Configure the FTDI interface as a SPI master"""
        self._frequency = self._ftdi.open_mpsse(
            vendor,
            product,
            interface,
            direction=self._direction,
            initial=self._cs_bits,  # /CS all high
            frequency=frequency,
        )

    def terminate(self):
        """Close the FTDI interface"""
        if self._ftdi:
            self._ftdi.close()
            self._ftdi = None

    def get_port(self, cs):
        """Obtain a SPI port to drive a SPI device selected by cs"""
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if cs >= len(self._ports):
            raise SpiIOError("No such SPI port")
        if not self._ports[cs]:
            cs_state = 0xFF & ~((SpiController.CS_BIT << cs) | SpiController.SCK_BIT | SpiController.DO_BIT)
            cs_cmd = Array("B", [Ftdi.SET_BITS_LOW, cs_state, self._direction])
            self._ports[cs] = SpiPort(self, cs_cmd)
            self._flush()
        return self._ports[cs]

    @property
    def frequency_max(self):
        """Returns the maximum SPI clock"""
        return self._ftdi.frequency_max

    @property
    def frequency(self):
        """Returns the current SPI clock"""
        return self._frequency

    def _exchange(self, frequency, cs_cmd, out, readlen):
        """Perform a half-duplex transaction with the SPI slave"""
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if len(out) > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Output payload is too large")
        if readlen > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Input payload is too large")
        if self._frequency != frequency:
            freq = self._ftdi.set_frequency(frequency)
            # store the requested value, not the actual one (best effort)
            self._frequency = frequency
        write_cmd = struct.pack("<BH", Ftdi.WRITE_BYTES_NVE_MSB, len(out) - 1)
        if readlen:
            read_cmd = struct.pack("<BH", Ftdi.READ_BYTES_NVE_MSB, readlen - 1)
            cmd = Array("B", cs_cmd)
            cmd.fromstring(write_cmd)
            cmd.extend(out)
            cmd.fromstring(read_cmd)
            cmd.extend(self._immediate)
            cmd.extend(self._cs_high)
            self._ftdi.write_data(cmd)
            # USB read cycle may occur before the FTDI device has actually
            # sent the data, so try to read more than once if no data is
            # actually received
            data = self._ftdi.read_data_bytes(readlen, 4)
        else:
            cmd = Array("B", cs_cmd)
            cmd.fromstring(write_cmd)
            cmd.extend(out)
            cmd.extend(self._cs_high)
            self._ftdi.write_data(cmd)
            data = Array("B")
        return data

    def _flush(self):
        """Flush the HW FIFOs"""
        self._ftdi.write_data(self._immediate)
        self._ftdi.purge_buffers()
Example #52
0
 def __init__(self, vendor, product, interface = 0):
     self.f = Ftdi()
     self.vendor = vendor
     self.product = product
     self.interface = interface
     self.f.open_bitbang(self.vendor, self.product, self.interface)
Example #53
0
class GPIOController(object):

    def __init__(self, vendor, product, interface = 0):
        self.f = Ftdi()
        self.vendor = vendor
        self.product = product
        self.interface = interface
        self.f.open_bitbang(self.vendor, self.product, self.interface)

    def read_pins(self):
        """
        Read all pins

        Args:
            Nothing

        Returns (int):
            All pins
        """
        return self.f.read_pins()

    def read_pin(self, bit_index):
        """
        Reads the pin specified by bit index:

        Args:
            bit_index (int): 0 - 15

        Returns (Boolean)
            True if set
            False if not set
        """
        bit_mask = 1 << bit_index
        return (self.f.read_pins() & bit_mask > 0)

    def enable_pin(self, bit_index, enable):
        """
        write out a single pin

        Args:
            bit_index (int):
                Index of bit to set
            enable (Boolean):
                True: Set
                False: Clear

        Returns: Nothing
        """
        bit_mask  = 1 << bit_index
        pins = self.f.read_pins()
        if enable:
            pins |= bit_mask
        else:
            pins &= ~bit_mask

        self.enable_pins(pins, enable)

    def enable_pins(self, bit_mask, enable):
        """
        write out multiple pins at one time 

        Args:
            bit_mask: The set of pins to be set or not set
                a 0 in a bit setting would set the pin low
                a 1 in a bit setting would set the pin high

        Returns: Nothing

        Example:
            enable_pins(bit_mask = 0x11)
            would set pins at address 0 and at address 4 high
            while the rest would be low
        """
        bit_mask = 0xFF & bit_mask
        if enable:
            self.f.write_data(Array('B', [0x01, bit_mask]))
        else:
            self.f.write_data(Array('B', [0x00, bit_mask]))

    def set_pin_direction_mask(self, pins):
        """
        Configure the GPIO direction

        Args:
            pins (integer): bitmask of pin direction
                1 = output, 0 = input

        Returns: Nothing

        Example:
            Set bit 0 and bit 4
            set_pin_direction_mask(0x11)

        Returns:
        """
        self.f.open_bitbang(self.vendor,
                            self.product,
                            self.interface,
                            direction = pins)
Example #54
0
class Sycamore (object):
	
	SYNC_FIFO_INTERFACE = 0
	SYNC_FIFO_INDEX = 0

	def __init__(self, idVendor, idProduct):
		self.vendor = idVendor
		self.product = idProduct
		self.dev = Ftdi()
		self.open_dev()

	def __del__(self):
		self.dev.close()

	def ping(self):
		data = Array('B', '0000'.decode('hex'))
		print "writing"
		for a in data:
			print "Data: %02X" % (a)

		self.dev.write_data(data)
		print "reading"

		time.sleep(.1)
		response = self.dev.read_data(4)
		rsp = Array('B')
		rsp.fromstring(response)
		print "rsp: " + str(rsp)
#		for a in rsp:
#			print "Data: %02X" % (a)

	def open_dev(self):
		frequency = 30.0E6
		latency = 2
		self.dev.open(self.vendor, self.product, 0)
	# Drain input buffer
		self.dev.purge_buffers()

		# Reset

		# Enable MPSSE mode
		self.dev.set_bitmode(0x00, Ftdi.BITMODE_SYNCFF)
		# Configure clock

		frequency = self.dev._set_frequency(frequency)
		# Set latency timer
		self.dev.set_latency_timer(latency)
		# Set chunk size
		self.dev.write_data_set_chunksize(0x10000)
		self.dev.read_data_set_chunksize(0x10000)
		
		self.dev.set_flowctrl('hw')
		# Configure I/O
#		self.write_data(Array('B', [Ftdi.SET_BITS_LOW, 0x00, 0x00]))
		# Disable loopback
#		self.write_data(Array('B', [Ftdi.LOOPBACK_END]))
#		self.validate_mpsse()
		# Drain input buffer
		self.dev.purge_buffers()
Example #55
0
File: spi.py Project: eblot/pyftdi
class SpiController(object):
    """SPI master.

        :param silent_clock: should be set to avoid clocking out SCLK when all
                             /CS signals are released. This clock beat is used
                             to enforce a delay between /CS signal activation.

                             When weird SPI devices are used, SCLK beating may
                             cause trouble. In this case, silent_clock should
                             be set but beware that SCLK line should be fitted
                             with a pull-down resistor, as SCLK is high-Z
                             during this short period of time.
        :param cs_count: is the number of /CS lines (one per device to drive on
                         the SPI bus)
    """

    SCK_BIT = 0x01
    DO_BIT = 0x02
    DI_BIT = 0x04
    CS_BIT = 0x08
    PAYLOAD_MAX_LENGTH = 0x10000  # 16 bits max

    def __init__(self, silent_clock=False, cs_count=4, turbo=True):
        self._ftdi = Ftdi()
        self._cs_bits = ((SpiController.CS_BIT << cs_count) - 1) & ~(SpiController.CS_BIT - 1)
        self._ports = [None] * cs_count
        self._direction = self._cs_bits | SpiController.DO_BIT | SpiController.SCK_BIT
        self._turbo = turbo
        self._cs_high = Array("B")
        if self._turbo:
            if silent_clock:
                # Set SCLK as input to avoid emitting clock beats
                self._cs_high.extend((Ftdi.SET_BITS_LOW, self._cs_bits, self._direction & ~SpiController.SCK_BIT))
            # /CS to SCLK delay, use 8 clock cycles as a HW tempo
            self._cs_high.extend((Ftdi.WRITE_BITS_TMS_NVE, 8 - 1, 0xFF))
        # Restore idle state
        self._cs_high.extend((Ftdi.SET_BITS_LOW, self._cs_bits, self._direction))
        if not self._turbo:
            self._cs_high.append(Ftdi.SEND_IMMEDIATE)
        self._immediate = Array("B", (Ftdi.SEND_IMMEDIATE,))
        self._frequency = 0.0

    def configure(self, vendor, product, interface, **kwargs):
        """Configure the FTDI interface as a SPI master"""
        for k in ("direction", "initial"):
            if k in kwargs:
                del kwargs[k]
        self._frequency = self._ftdi.open_mpsse(
            vendor, product, interface, direction=self._direction, initial=self._cs_bits, **kwargs  # /CS all high
        )

    def terminate(self):
        """Close the FTDI interface"""
        if self._ftdi:
            self._ftdi.close()
            self._ftdi = None

    def get_port(self, cs):
        """Obtain a SPI port to drive a SPI device selected by cs"""
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if cs >= len(self._ports):
            raise SpiIOError("No such SPI port")
        if not self._ports[cs]:
            cs_state = 0xFF & ~((SpiController.CS_BIT << cs) | SpiController.SCK_BIT | SpiController.DO_BIT)
            cs_cmd = Array("B", (Ftdi.SET_BITS_LOW, cs_state, self._direction))
            self._ports[cs] = SpiPort(self, cs_cmd)
            self._flush()
        return self._ports[cs]

    @property
    def frequency_max(self):
        """Returns the maximum SPI clock"""
        return self._ftdi.frequency_max

    @property
    def frequency(self):
        """Returns the current SPI clock"""
        return self._frequency

    def _exchange(self, frequency, out, readlen, cs_cmd=None, complete=True):
        """Perform a half-duplex exchange or transaction with the SPI slave

           :param frequency: SPI bus clock
           :param out: an array of bytes to send to the SPI slave,
                       may be empty to only read out data from the slave
           :param readlen: count of bytes to read out from the slave,
                       may be zero to only write to the slave
           :param cs_cmd: the prolog sequence to activate the /CS line on the
                       SPI bus. May be empty to resume a previously started
                       transaction
           :param complete: whether to send the epilog sequence to move the
                       /CS line back to the idle state. May be force to False
                       if another part of a transaction is expected
           :return: an array of bytes containing the data read out from the
                    slave
        """
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if len(out) > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Output payload is too large")
        if readlen > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Input payload is too large")
        if self._frequency != frequency:
            self._ftdi.set_frequency(frequency)
            # store the requested value, not the actual one (best effort)
            self._frequency = frequency
        cmd = cs_cmd and Array("B", cs_cmd) or Array("B")
        writelen = len(out)
        if writelen:
            write_cmd = struct.pack("<BH", Ftdi.WRITE_BYTES_NVE_MSB, writelen - 1)
            if PY3:
                cmd.frombytes(write_cmd)
            else:
                cmd.fromstring(write_cmd)
            cmd.extend(out)
        if readlen:
            read_cmd = struct.pack("<BH", Ftdi.READ_BYTES_NVE_MSB, readlen - 1)
            if PY3:
                cmd.frombytes(read_cmd)
            else:
                cmd.fromstring(read_cmd)
            cmd.extend(self._immediate)
            if self._turbo:
                if complete:
                    cmd.extend(self._cs_high)
                self._ftdi.write_data(cmd)
            else:
                self._ftdi.write_data(cmd)
                if complete:
                    self._ftdi.write_data(self._cs_high)
            # USB read cycle may occur before the FTDI device has actually
            # sent the data, so try to read more than once if no data is
            # actually received
            data = self._ftdi.read_data_bytes(readlen, 4)
        elif writelen:
            if self._turbo:
                if complete:
                    cmd.extend(self._cs_high)
                self._ftdi.write_data(cmd)
            else:
                self._ftdi.write_data(cmd)
                if complete:
                    self._ftdi.write_data(self._cs_high)
            data = Array("B")
        return data

    def _flush(self):
        """Flush the HW FIFOs"""
        self._ftdi.write_data(self._immediate)
        self._ftdi.purge_buffers()
Example #56
0
class SpiController:
    """SPI master.

        :param silent_clock: deprecated.
        :param int cs_count: is the number of /CS lines (one per device to
            drive on the SPI bus)
        :param boolean turbo: to be documented
    """

    SCK_BIT = 0x01
    DO_BIT = 0x02
    DI_BIT = 0x04
    CS_BIT = 0x08
    SPI_BITS = DI_BIT | DO_BIT | SCK_BIT
    PAYLOAD_MAX_LENGTH = 0x10000  # 16 bits max

    def __init__(self, silent_clock=False, cs_count=4, turbo=True):
        self.log = getLogger('pyftdi.spi.ctrl')
        self._ftdi = Ftdi()
        self._lock = Lock()
        self._gpio_port = None
        self._gpio_dir = 0
        self._gpio_mask = 0
        self._gpio_low = 0
        self._wide_port = False
        self._cs_count = cs_count
        self._turbo = turbo
        self._immediate = bytes((Ftdi.SEND_IMMEDIATE,))
        self._frequency = 0.0
        self._clock_phase = False

    @property
    def direction(self):
        """Provide the FTDI GPIO direction"""
        return self._spi_dir | self._gpio_dir

    def configure(self, url, **kwargs):
        """Configure the FTDI interface as a SPI master

           :param str url: FTDI URL string, such as 'ftdi://ftdi:232h/1'
           :param kwargs: options to configure the SPI bus

           Accepted options:

           * ``frequency`` the SPI bus frequency in Hz. Note that each slave
                          may reconfigure the SPI bus with a specialized
                          frequency.
           * ``cs_count`` count of chip select signals dedicated to select
                          SPI slave devices
           * ``turbo`` whether to enable or disable turbo mode
           * ``debug`` for extra debug output
        """
        # it is better to specify CS and turbo in configure, but the older
        # API where these parameters are specified at instanciation has been
        # preserved
        self._cs_count = int(kwargs.get('cs_count', self._cs_count))
        if not (1 <= self._cs_count <= 5):
            raise ValueError('Unsupported CS line count: %d' % self._cs_count)
        self._turbo = bool(kwargs.get('turbo', self._turbo))
        for k in ('direction', 'initial', 'cs_count', 'turbo'):
            if k in kwargs:
                del kwargs[k]
        with self._lock:
            if self._frequency > 0.0:
                raise SpiIOError('Already configured')
            self._cs_bits = (((SpiController.CS_BIT << self._cs_count) - 1) &
                             ~(SpiController.CS_BIT - 1))
            self._spi_ports = [None] * self._cs_count
            self._spi_dir = (self._cs_bits |
                             SpiController.DO_BIT |
                             SpiController.SCK_BIT)
            self._spi_mask = self._cs_bits | self.SPI_BITS
            self._frequency = self._ftdi.open_mpsse_from_url(
                # /CS all high
                url, direction=self._spi_dir, initial=self._cs_bits, **kwargs)
            self._ftdi.enable_adaptive_clock(False)
            self._wide_port = self._ftdi.has_wide_port

    def terminate(self):
        """Close the FTDI interface"""
        if self._ftdi:
            self._ftdi.close()
        self._frequency = 0.0

    def get_port(self, cs, freq=None, mode=0):
        """Obtain a SPI port to drive a SPI device selected by Chip Select.

           :note: SPI mode 2 is not supported.

           :param int cs: chip select slot, starting from 0
           :param float freq: SPI bus frequency for this slave in Hz
           :param int mode: SPI mode [0,1,3]
           :rtype: SpiPort
        """
        with self._lock:
            if not self._ftdi:
                raise SpiIOError("FTDI controller not initialized")
            if cs >= len(self._spi_ports):
                raise SpiIOError("No such SPI port")
            if not (0 <= mode <= 3):
                raise SpiIOError("Invalid SPI mode")
            if (mode & 0x2) and not self._ftdi.is_H_series:
                raise SpiIOError("SPI with CPHA high is not supported by "
                                 "this FTDI device")
            if mode == 2:
                raise SpiIOError("SPI mode 2 has no known workaround with "
                                 "FTDI devices")
            if not self._spi_ports[cs]:
                freq = min(freq or self._frequency, self.frequency_max)
                hold = freq and (1+int(1E6/freq))
                self._spi_ports[cs] = SpiPort(self, cs, cs_hold=hold,
                                              spi_mode=mode)
                self._spi_ports[cs].set_frequency(freq)
                self._flush()
            return self._spi_ports[cs]

    def get_gpio(self):
        with self._lock:
            if not self._ftdi:
                raise SpiIOError("FTDI controller not initialized")
            if not self._gpio_port:
                self._gpio_port = SpiGpioPort(self)
            return self._gpio_port

    @property
    def frequency_max(self):
        """Returns the maximum SPI clock"""
        return self._ftdi.frequency_max

    @property
    def frequency(self):
        """Returns the current SPI clock"""
        return self._frequency

    @property
    def gpio_pins(self):
        """Report the addressable GPIOs as a bitfield"""
        with self._lock:
            return self._gpio_mask

    def exchange(self, frequency, out, readlen,
                 cs_prolog=None, cs_epilog=None,
                 cpol=False, cpha=False, duplex=False):
        if duplex:
            if readlen > len(out):
                tmp = array('B', out)
                tmp.extend([0] * (readlen - len(out)))
                out = tmp
            elif not readlen:
                readlen = len(out)
        with self._lock:
            if duplex:
                data = self._exchange_full_duplex(frequency, out,
                                                  cs_prolog, cs_epilog,
                                                  cpol, cpha)
                return data[:readlen]
            else:
                return self._exchange_half_duplex(frequency, out, readlen,
                                                  cs_prolog, cs_epilog,
                                                  cpol, cpha)

    def read_gpio(self, with_output=False):
        """Read GPIO port

           :param bool with_output: set to unmask output pins
           :return: the GPIO port pins as a bitfield
           :rtype: int
        """
        with self._lock:
            data = self._read_raw(self._wide_port)
        value = data & self._gpio_mask
        if not with_output:
            value &= ~self._gpio_dir
        return value

    def write_gpio(self, value):
        """Write GPIO port

           :param int value: the GPIO port pins as a bitfield
        """
        with self._lock:
            if (value & self._gpio_dir) != value:
                raise SpiIOError('No such GPO pins: %04x/%04x' %
                                 (self._gpio_dir, value))
            # perform read-modify-write
            use_high = self._wide_port and (self.direction & 0xff00)
            data = self._read_raw(use_high)
            data &= ~self._gpio_mask
            data |= value
            self._write_raw(data, use_high)
            self._gpio_low = data & 0xFF & ~self._spi_mask

    def set_gpio_direction(self, pins, direction):
        """Change the direction of the GPIO pins

           :param int pins: which GPIO pins should be reconfigured
           :param int direction: direction bitfield (on for output)
        """
        with self._lock:
            if pins & self._spi_mask:
                raise SpiIOError('Cannot access SPI pins as GPIO')
            gpio_width = self._wide_port and 16 or 8
            gpio_mask = (1 << gpio_width) - 1
            gpio_mask &= ~self._spi_mask
            if (pins & gpio_mask) != pins:
                raise SpiIOError('No such GPIO pin(s)')
            self._gpio_dir &= ~pins
            self._gpio_dir |= (pins & direction)
            self._gpio_mask = gpio_mask & pins

    def _read_raw(self, read_high):
        if read_high:
            cmd = array('B', [Ftdi.GET_BITS_LOW,
                              Ftdi.GET_BITS_HIGH,
                              Ftdi.SEND_IMMEDIATE])
            fmt = '<H'
        else:
            cmd = array('B', [Ftdi.GET_BITS_LOW,
                              Ftdi.SEND_IMMEDIATE])
            fmt = 'B'
        self._ftdi.write_data(cmd)
        size = scalc(fmt)
        data = self._ftdi.read_data_bytes(size, 4)
        if len(data) != size:
            raise SpiIOError('Cannot read GPIO')
        value, = sunpack(fmt, data)
        return value

    def _write_raw(self, data, write_high):
        direction = self.direction
        low_data = data & 0xFF
        low_dir = direction & 0xFF
        if write_high:
            high_data = (data >> 8) & 0xFF
            high_dir = (direction >> 8) & 0xFF
            cmd = array('B', [Ftdi.SET_BITS_LOW, low_data, low_dir,
                              Ftdi.SET_BITS_HIGH, high_data, high_dir])
        else:
            cmd = array('B', [Ftdi.SET_BITS_LOW, low_data, low_dir])
        self._ftdi.write_data(cmd)

    def _exchange_half_duplex(self, frequency, out, readlen,
                              cs_prolog, cs_epilog, cpol, cpha):
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if len(out) > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Output payload is too large")
        if readlen > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Input payload is too large")
        if cpha:
            # to enable CPHA, we need to use a workaround with FTDI device,
            # that is enable 3-phase clocking (which is usually dedicated to
            # I2C support). This mode use use 3 clock period instead of 2,
            # which implies the FTDI frequency should be fixed to match the
            # requested one.
            frequency = (3*frequency)//2
        if self._frequency != frequency:
            self._ftdi.set_frequency(frequency)
            # store the requested value, not the actual one (best effort),
            # to avoid setting unavailable values on each call.
            self._frequency = frequency
        direction = self.direction & 0xFF  # low bits only
        cmd = array('B')
        for ctrl in cs_prolog or []:
            ctrl &= self._spi_mask
            ctrl |= self._gpio_low
            cmd.extend((Ftdi.SET_BITS_LOW, ctrl, direction))
        epilog = array('B')
        if cs_epilog:
            for ctrl in cs_epilog:
                ctrl &= self._spi_mask
                ctrl |= self._gpio_low
                epilog.extend((Ftdi.SET_BITS_LOW, ctrl, direction))
            # Restore idle state
            cs_high = [Ftdi.SET_BITS_LOW, self._cs_bits | self._gpio_low,
                       direction]
            if not self._turbo:
                cs_high.append(Ftdi.SEND_IMMEDIATE)
            epilog.extend(cs_high)
        writelen = len(out)
        if self._clock_phase != cpha:
            self._ftdi.enable_3phase_clock(cpha)
            self._clock_phase = cpha
        if writelen:
            wcmd = (cpol ^ cpha) and \
                Ftdi.WRITE_BYTES_PVE_MSB or Ftdi.WRITE_BYTES_NVE_MSB
            write_cmd = spack('<BH', wcmd, writelen-1)
            cmd.frombytes(write_cmd)
            cmd.extend(out)
        if readlen:
            rcmd = (cpol ^ cpha) and \
                Ftdi.READ_BYTES_PVE_MSB or Ftdi.READ_BYTES_NVE_MSB
            read_cmd = spack('<BH', rcmd, readlen-1)
            cmd.frombytes(read_cmd)
            cmd.extend(self._immediate)
            if self._turbo:
                if epilog:
                    cmd.extend(epilog)
                self._ftdi.write_data(cmd)
            else:
                self._ftdi.write_data(cmd)
                if epilog:
                    self._ftdi.write_data(epilog)
            # USB read cycle may occur before the FTDI device has actually
            # sent the data, so try to read more than once if no data is
            # actually received
            data = self._ftdi.read_data_bytes(readlen, 4)
        else:
            if writelen:
                if self._turbo:
                    if epilog:
                        cmd.extend(epilog)
                    self._ftdi.write_data(cmd)
                else:
                    self._ftdi.write_data(cmd)
                    if epilog:
                        self._ftdi.write_data(epilog)
            data = array('B')
        return data

    def _exchange_full_duplex(self, frequency, out,
                              cs_prolog, cs_epilog, cpol, cpha):
        if not self._ftdi:
            raise SpiIOError("FTDI controller not initialized")
        if len(out) > SpiController.PAYLOAD_MAX_LENGTH:
            raise SpiIOError("Output payload is too large")
        if cpha:
            # to enable CPHA, we need to use a workaround with FTDI device,
            # that is enable 3-phase clocking (which is usually dedicated to
            # I2C support). This mode use use 3 clock period instead of 2,
            # which implies the FTDI frequency should be fixed to match the
            # requested one.
            frequency = (3*frequency)//2
        if self._frequency != frequency:
            self._ftdi.set_frequency(frequency)
            # store the requested value, not the actual one (best effort),
            # to avoid setting unavailable values on each call.
            self._frequency = frequency
        direction = self.direction & 0xFF  # low bits only
        cmd = array('B')
        for ctrl in cs_prolog or []:
            ctrl &= self._spi_mask
            ctrl |= self._gpio_low
            cmd.extend((Ftdi.SET_BITS_LOW, ctrl, direction))
        epilog = array('B')
        if cs_epilog:
            for ctrl in cs_epilog:
                ctrl &= self._spi_mask
                ctrl |= self._gpio_low
                epilog.extend((Ftdi.SET_BITS_LOW, ctrl, direction))
            # Restore idle state
            cs_high = [Ftdi.SET_BITS_LOW, self._cs_bits | self._gpio_low,
                       direction]
            if not self._turbo:
                cs_high.append(Ftdi.SEND_IMMEDIATE)
            epilog.extend(cs_high)
        writelen = len(out)
        if self._clock_phase != cpha:
            self._ftdi.enable_3phase_clock(cpha)
            self._clock_phase = cpha
        wcmd = (cpol ^ cpha) and \
            Ftdi.RW_BYTES_NVE_PVE_MSB or Ftdi.RW_BYTES_PVE_NVE_MSB
        write_cmd = spack('<BH', wcmd, writelen-1)
        cmd.frombytes(write_cmd)
        cmd.extend(out)
        cmd.extend(self._immediate)
        if self._turbo:
            if epilog:
                cmd.extend(epilog)
            self._ftdi.write_data(cmd)
        else:
            self._ftdi.write_data(cmd)
            if epilog:
                self._ftdi.write_data(epilog)
        # USB read cycle may occur before the FTDI device has actually
        # sent the data, so try to read more than once if no data is
        # actually received
        data = self._ftdi.read_data_bytes(len(out), 4)
        return data

    def _flush(self):
        """Flush the HW FIFOs"""
        self._ftdi.write_data(self._immediate)
        self._ftdi.purge_buffers()
Example #57
0
 def test_multiple_interface(self):
     # the following calls used to create issues (several interfaces from
     # the same device)
     ftdi1 = Ftdi()
     ftdi1.open(interface=1)
     ftdi2 = Ftdi()
     ftdi2.open(interface=2)
     import time
     for x in range(5):
         print "If#1: ", hex(ftdi1.poll_modem_status())
         print "If#2: ", ftdi2.modem_status()
         time.sleep(0.500)
     ftdi1.close()
     ftdi2.close()
Example #58
0
	def __init__(self, idVendor, idProduct):
		self.vendor = idVendor
		self.product = idProduct
		self.f = Ftdi()
Example #59
0
class FTDI_DAQ(Instrument):
    _ports = []
    _port = None
    _last_byte = chr(0)
    _aliases = {}

    def __init__(self, name, serial = None, port = 'A', baudrate = 115200):
        '''
            discover and initialize Tunnel_DAC hardware
            
            Input:
                serial - serial number of the FTDI converter
                channel - 2 character channel id the DAC is connected to;
                    the first byte identifies the channel (A..D for current devices)
                    the second byte identifies the bit within that channel (0..7)
                numdacs - number of DACs daisy-chained on that line
                delay - communications delay assumed between PC and the USB converter
        '''
        logging.info(__name__+ ': Initializing instrument Tunnel_DAC')
        Instrument.__init__(self, name, tags=['physical'])
        
        self._conn = Ftdi()
        # VIDs and PIDs of converters used
        vps = [
            (0x0403, 0x6011), # FTDI UM4232H 4ch
            (0x0403, 0x6014)  # FTDI UM232H 1ch
        ]
        # explicitly clear device cache of UsbTools
        #UsbTools.USBDEVICES = []
        # find all devices and obtain serial numbers
        devs = self._conn.find_all(vps)
        # filter list by serial number if provided
        if(serial != None):
            devs = [dev for dev in devs if dev[2] == serial]
        if(len(devs) == 0):
            logging.error(__name__ + ': failed to find matching FTDI devices.')
        elif(len(devs) > 1):
            logging.error(__name__ + ': more than one converter found and no serial number given.')
            logging.info(__name__ + ': available devices are: %s.'%str([dev[2] for dev in devs]))
        vid, pid, self._serial, ports, description = devs[0]
        self._ports = [chr(ord('A') + i) for i in range(ports)]

        # open device
        (self._port, bit) = self._parse_channel_string(port)
        self._conn.open(vid, pid, interface = ord(self._port) - ord('A') + 1, serial = self._serial)
        logging.info(__name__ + ': using converter with serial #%s'%self._serial)
        self._conn.set_bitmode(0xFF, Ftdi.BITMODE_BITBANG)
        self._set_baudrate(baudrate)

        # provide user interface
        self.add_parameter('port', type=types.StringType, flags=Instrument.FLAG_GET)
        #self.add_parameter('aliases', type=types.DictType, flags=Instrument.FLAG_GETSET)
        self.add_function('digital_out')
        self.add_function('digital_stream')
        self.add_function('set_aliases')
        self.add_function('get_aliases')

    def do_get_port(self):
        return self._port

    def set_aliases(self, aliases):
        '''
            define channel aliases
            accepts a dictionary that resolves alias names to internal channel names
        '''
        self._aliases = aliases
    
    def get_aliases(self):
        '''
            retrieve channel aliases
        '''
        return self._aliases

    def digital_out(self, channel, status):
        '''
            set a bit/byte on a FTDI channel
        '''
        (port, bit) = self._parse_channel_string(channel)
        if(bit != None):
            if(status): 
                byte = chr(ord(self._last_byte) | (1<<bit))
            else:
                byte = chr(ord(self._last_byte) & ~(1<<bit))
        else:
            byte = chr(0xff) if status else chr(0)
        self._conn.write_data(byte)
        self._last_byte = byte

    def digital_stream(self, channel, samples, rate):
        '''
            write a serial bit/byte stream to the device
        '''
        (port, bit) = self._parse_channel_string(channel)
        # convert bit stream into byte stream
        if(bit != None):
            byte = 1<<bit
            samples = [(chr(ord(self._lastbyte) | byte) if x else (chr(ord(self._lastbyte) & ~byte))) for x in BitArray(samples)]
        # output data on the device
        self._set_baudrate(rate)
        self._conn.write_data(samples)
        self._last_byte = samples[-1]

    def _parse_channel_string(self, channel):
        '''
            parses a channel string into a (port, bit) tuple
        '''
        # translate aliases
        if(self._aliases.has_key(channel)):
            channel = self._aliases[channel]
        
        # parse & mangle channel string
        m = re.match('(?P<port>[A-Z]+[0-9]*)(?P<bit>:[0-9]+)?', channel).groupdict()
        if(m == None):
            raise ValueError('channel identifier %s not understood.'%channel)
        port = m['port']
        if(m['bit'] != None): 
            bit = int(m['bit'].lstrip(':'))
        else:
            bit = None
        
        # check if the channel exists on this device
        if(not (port in self._ports)):
            raise ValueError('prot %s not supported by this device.'%port)
        if((self._port != None) and (port != self._port)):
            raise ValueError('this implementation can not change the port identifier outside __init__.')
        if((bit != None) and ((bit < 0) or (bit > 7))):
            raise ValueError('bit number must be between 0 and 7, not %d.'%bit)
        
        return (port, bit)
        
    def _set_baudrate(self, baudrate):
        ''' 
            change baud rate of the FTDIs serial engine
        '''
        # 80k generates bit durations of 12.5us, 80 is magic :(
        # magic?: 4 from incorrect BITBANG handling of pyftdi, 2.5 from 120MHz instead of 48MHz clock of H devices
        self._baudrate =  baudrate
        self._conn.set_baudrate(baudrate/80)
Example #60
0
class HapticStimulator(object):
    '''
    Class to initialise and send commands to sensory stimulator built 
    on FTDI FT2232HL with power trasistors board
    ("fMRI Pneumatic 5V version") from Politechnika Warszawska
    '''
    def __init__(self, vendorid=VENDORID, productid=PRODUCTID,
                        interface=DEFAULTINTERFACE):
        '''
        Initialises FTDI device as Haptic Stimulator
        
        :param vendorid: int or hex NOT string
        gotten from lsusb for FTDI device
        :param productid: int or hex NOT string
        gotten from lsusb for FTDI device
        :param interface: int - for tested board is always 2'''
        self.ftdi = Ftdi()
        self.ftdi.open_bitbang(vendorid, productid, interface, 
                                direction = 0xFF)
                                # direction FF - all ports output
        self.lock = threading.RLock()
        self.ftdi.write_data([0]) # turn off all channels
        
    def __del__(self):
        self.close()
    
    def _turn_off(self, chnl):
        '''
        Will turn off selected channel, used by stimulate method on
        on timer
        
        :param chnl: int - number of channel to turn off
        '''
        with self.lock:
            apins = self.ftdi.read_pins()
            activation_mask = ~(1 << (chnl-1)) & 0xFF #select only 
                                                      #needed channel
            self.ftdi.write_data([apins & activation_mask])
    
    def stimulate(self, chnl, time):
        '''
        Turn on stimulation on channel number chnl for time seconds
        
        :param chnl: integer - channel number starting from 1
        :param time: float - stimulation length in seconds
        '''
        t = threading.Timer(time, self._turn_off, [chnl]) # we expect 
                                                #short times ~ seconds
                                                #handling timers 
                                                #should not matter
        t.daemon = True # timer thread shall end immediately at main
                        # program shutdown, because interface must be
                        # closed by then and every channel turned off by
                        # .close() method. No need to wait for 
                        # schedueled stimulation end.
        t.start()
        with self.lock:
            apins = self.ftdi.read_pins()
            activation_mask = 1 << (chnl-1) # create byte with bit on
                                            # corresponding channel
                                            # enabled
            self.ftdi.write_data([apins | activation_mask]) #add active bit
                                                       # to other active
                                                       # channels
        
        
    def bulk_stimulate(self, chnls, times):
        '''
        Enables multiple channels for some time in seconds
        
        len(chnls) should be equal to len(times)
        
        :param chnls: list of integers - channels to activate
        :param times: list of floats - activation time lenghts for
        corresponding channel
        '''
        if len(chnls) != len(times):
            raise Exception(
              'Stimulation channels and times are not the same length!'
                )
        for c, t in zip(chnls, times):
            self.stimulate(c, t)
    
    def close(self):
        '''Releasing device'''
        self.ftdi.write_data([0]) # turn off all channels
        self.ftdi.usb_dev.reset() # release device