예제 #1
0
 def __init__(self, silent_clock=False, cs_count=4):
     """Instanciate a SpiController.
        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.
        cs_count is the number of /CS lines (one per device to drive on the
        SPI bus)
     """
     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
예제 #2
0
    def __init__(self, interface=0, vid=None, pid=None):
        """
        Constructor

        :param interface: May specify either the serial number or the device
                          index.
        :type interface: string or int
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        Device.__init__(self)

        self._device = Ftdi()

        self._interface = 0
        self._device_number = 0
        self._serial_number = None

        self._vendor_id = USBDevice.DEFAULT_VENDOR_ID
        if vid:
            self._vendor_id = vid

        self._product_id = USBDevice.DEFAULT_PRODUCT_ID
        if pid:
            self._product_id = pid

        self._endpoint = 0
        self._description = None

        self.interface = interface
예제 #3
0
  def __init__(self, idVendor=0x0403, idProduct=0x8530, debug = False):
    Olympus.__init__(self, debug)
    self.vendor = idVendor
    self.product = idProduct
    self.dev = Ftdi()
    self._open_dev()

    self.name = "Dionysus"
예제 #4
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()
        #    print "vid: %s, pid: %s" % (str(hex(idVendor)), str(hex(idProduct)))
        self.f.open_bitbang(idVendor, idProduct, interface)
예제 #5
0
파일: jtag.py 프로젝트: greyseason/pyftdi
 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')
예제 #6
0
    def __init__(self, interface=0, vid=None, pid=None):
        """
        Constructor

        :param interface: May specify either the serial number or the device
                          index.
        :type interface: string or int
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        Device.__init__(self)

        self._device = Ftdi()

        self._interface = 0
        self._device_number = 0
        self._serial_number = None

        self._vendor_id = USBDevice.DEFAULT_VENDOR_ID
        if vid:
            self._vendor_id = vid

        self._product_id = USBDevice.DEFAULT_PRODUCT_ID
        if pid:
            self._product_id = pid

        self._endpoint = 0
        self._description = None

        self.interface = interface
예제 #7
0
파일: spi.py 프로젝트: etihwnad/pyftdi
 def __init__(self, silent_clock=False, cs_count=4):
     """Instanciate a SpiController.
        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.
        cs_count is the number of /CS lines (one per device to drive on the
        SPI bus)
     """
     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
예제 #8
0
    def find_all(cls, vid=None, pid=None):
        """
        Returns all FTDI devices matching our vendor and product IDs.

        :returns: list of devices
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        cls.__devices = []

        query = cls.PRODUCT_IDS
        if vid and pid:
            query = [(vid, pid)]

        try:
            cls.__devices = Ftdi.find_all(query, nocache=True)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError(
                'Error enumerating AD2USB devices: {0}'.format(str(err)), err)

        return cls.__devices
예제 #9
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()
#    print "vid: %s, pid: %s" % (str(hex(idVendor)), str(hex(idProduct)))
    self.f.open_bitbang(idVendor, idProduct, interface)
예제 #10
0
파일: spi.py 프로젝트: greyseason/pyftdi
 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
예제 #11
0
파일: jtag.py 프로젝트: Tfou57/robomow
 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')
예제 #12
0
    def find_all(cls, vid=None, pid=None):
        """
        Returns all FTDI devices matching our vendor and product IDs.

        :returns: list of devices
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        cls.__devices = []

        query = cls.PRODUCT_IDS
        if vid and pid:
            query = [(vid, pid)]

        try:
            cls.__devices = Ftdi.find_all(query, nocache=True)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)

        return cls.__devices
예제 #13
0
class USBDevice(Device):
    """
    `AD2USB`_ device utilizing PyFTDI's interface.
    """

    # Constants
    PRODUCT_IDS = ((0x0403, 0x6001), (0x0403, 0x6015))
    """List of Vendor and Product IDs used to recognize `AD2USB`_ devices."""
    DEFAULT_VENDOR_ID = PRODUCT_IDS[0][0]
    """Default Vendor ID used to recognize `AD2USB`_ devices."""
    DEFAULT_PRODUCT_ID = PRODUCT_IDS[0][1]
    """Default Product ID used to recognize `AD2USB`_ devices."""

    # Deprecated constants
    FTDI_VENDOR_ID = DEFAULT_VENDOR_ID
    """DEPRECATED: Vendor ID used to recognize `AD2USB`_ devices."""
    FTDI_PRODUCT_ID = DEFAULT_PRODUCT_ID
    """DEPRECATED: Product ID used to recognize `AD2USB`_ devices."""

    BAUDRATE = 115200
    """Default baudrate for `AD2USB`_ devices."""

    __devices = []
    __detect_thread = None

    @classmethod
    def find_all(cls, vid=None, pid=None):
        """
        Returns all FTDI devices matching our vendor and product IDs.

        :returns: list of devices
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        cls.__devices = []

        query = cls.PRODUCT_IDS
        if vid and pid:
            query = [(vid, pid)]

        try:
            cls.__devices = Ftdi.find_all(query, nocache=True)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError(
                'Error enumerating AD2USB devices: {0}'.format(str(err)), err)

        return cls.__devices

    @classmethod
    def devices(cls):
        """
        Returns a cached list of `AD2USB`_ devices located on the system.

        :returns: cached list of devices found
        """
        return cls.__devices

    @classmethod
    def find(cls, device=None):
        """
        Factory method that returns the requested :py:class:`USBDevice` device, or the
        first device.

        :param device: Tuple describing the USB device to open, as returned
                       by find_all().
        :type device: tuple

        :returns: :py:class:`USBDevice` object utilizing the specified device
        :raises: :py:class:`~alarmdecoder.util.NoDeviceError`
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        cls.find_all()

        if len(cls.__devices) == 0:
            raise NoDeviceError('No AD2USB devices present.')

        if device is None:
            device = cls.__devices[0]

        vendor, product, sernum, ifcount, description = device

        return USBDevice(interface=sernum, vid=vendor, pid=product)

    @classmethod
    def start_detection(cls, on_attached=None, on_detached=None):
        """
        Starts the device detection thread.

        :param on_attached: function to be called when a device is attached  **Callback definition:** *def callback(thread, device)*
        :type on_attached: function
        :param on_detached: function to be called when a device is detached  **Callback definition:** *def callback(thread, device)*

        :type on_detached: function
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        cls.__detect_thread = USBDevice.DetectThread(on_attached, on_detached)

        try:
            cls.find_all()
        except CommError:
            pass

        cls.__detect_thread.start()

    @classmethod
    def stop_detection(cls):
        """
        Stops the device detection thread.
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        try:
            cls.__detect_thread.stop()

        except Exception:
            pass

    @property
    def interface(self):
        """
        Retrieves the interface used to connect to the device.

        :returns: the interface used to connect to the device
        """
        return self._interface

    @interface.setter
    def interface(self, value):
        """
        Sets the interface used to connect to the device.

        :param value: may specify either the serial number or the device index
        :type value: string or int
        """
        self._interface = value
        if isinstance(value, int):
            self._device_number = value
        else:
            self._serial_number = value

    @property
    def serial_number(self):
        """
        Retrieves the serial number of the device.

        :returns: serial number of the device
        """

        return self._serial_number

    @serial_number.setter
    def serial_number(self, value):
        """
        Sets the serial number of the device.

        :param value: serial number of the device
        :type value: string
        """
        self._serial_number = value

    @property
    def description(self):
        """
        Retrieves the description of the device.

        :returns: description of the device
        """
        return self._description

    @description.setter
    def description(self, value):
        """
        Sets the description of the device.

        :param value: description of the device
        :type value: string
        """
        self._description = value

    def __init__(self, interface=0, vid=None, pid=None):
        """
        Constructor

        :param interface: May specify either the serial number or the device
                          index.
        :type interface: string or int
        """
        if not have_pyftdi:
            raise ImportError(
                'The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.'
            )

        Device.__init__(self)

        self._device = Ftdi()

        self._interface = 0
        self._device_number = 0
        self._serial_number = None

        self._vendor_id = USBDevice.DEFAULT_VENDOR_ID
        if vid:
            self._vendor_id = vid

        self._product_id = USBDevice.DEFAULT_PRODUCT_ID
        if pid:
            self._product_id = pid

        self._endpoint = 0
        self._description = None

        self.interface = interface

    def open(self, baudrate=BAUDRATE, no_reader_thread=False):
        """
        Opens the device.

        :param baudrate: baudrate to use
        :type baudrate: int
        :param no_reader_thread: whether or not to automatically start the
                                 reader thread.
        :type no_reader_thread: bool

        :raises: :py:class:`~alarmdecoder.util.NoDeviceError`
        """
        # Set up defaults
        if baudrate is None:
            baudrate = USBDevice.BAUDRATE

        self._read_thread = Device.ReadThread(self)

        # Open the device and start up the thread.
        try:
            self._device.open(self._vendor_id, self._product_id,
                              self._endpoint, self._device_number,
                              self._serial_number, self._description)

            self._device.set_baudrate(baudrate)

            if not self._serial_number:
                self._serial_number = self._get_serial_number()

            self._id = self._serial_number

        except (usb.core.USBError, FtdiError) as err:
            raise NoDeviceError('Error opening device: {0}'.format(str(err)),
                                err)

        except KeyError as err:
            raise NoDeviceError(
                'Unsupported device. ({0:04x}:{1:04x})  You probably need a newer version of pyftdi.'
                .format(err[0][0], err[0][1]))

        else:
            self._running = True
            self.on_open()

            if not no_reader_thread:
                self._read_thread.start()

        return self

    def close(self):
        """
        Closes the device.
        """
        try:
            Device.close(self)

            # HACK: Probably should fork pyftdi and make this call in .close()
            self._device.usb_dev.attach_kernel_driver(self._device_number)

        except Exception:
            pass

    def fileno(self):
        """
        File number not supported for USB devices.
    
        :raises: NotImplementedError
        """
        raise NotImplementedError('USB devices do not support fileno()')

    def write(self, data):
        """
        Writes data to the device.

        :param data: data to write
        :type data: string

        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        try:
            self._device.write_data(data)

            self.on_write(data=data)

        except FtdiError as err:
            raise CommError('Error writing to device: {0}'.format(str(err)),
                            err)

    def read(self):
        """
        Reads a single character from the device.

        :returns: character read from the device
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        ret = None

        try:
            ret = self._device.read_data(1)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error reading from device: {0}'.format(str(err)),
                            err)

        return ret

    def read_line(self, timeout=0.0, purge_buffer=False):
        """
        Reads a line from the device.

        :param timeout: read timeout
        :type timeout: float
        :param purge_buffer: Indicates whether to purge the buffer prior to
                             reading.
        :type purge_buffer: bool

        :returns: line that was read
        :raises: :py:class:`~alarmdecoder.util.CommError`, :py:class:`~alarmdecoder.util.TimeoutError`
        """
        def timeout_event():
            """Handles read timeout event"""
            timeout_event.reading = False

        timeout_event.reading = True

        if purge_buffer:
            self._buffer = b''

        got_line, ret = False, None

        timer = threading.Timer(timeout, timeout_event)
        if timeout > 0:
            timer.start()

        try:
            while timeout_event.reading:
                buf = self._device.read_data(1)

                if buf != b'':
                    ub = bytes_hack(buf)

                    self._buffer += ub

                    if ub == b"\n":
                        self._buffer = self._buffer.rstrip(b"\r\n")

                        if len(self._buffer) > 0:
                            got_line = True
                            break
                else:
                    time.sleep(0.01)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error reading from device: {0}'.format(str(err)),
                            err)

        else:
            if got_line:
                ret, self._buffer = self._buffer, b''

                self.on_read(data=ret)

            else:
                raise TimeoutError(
                    'Timeout while waiting for line terminator.')

        finally:
            timer.cancel()

        return ret

    def purge(self):
        """
        Purges read/write buffers.
        """
        self._device.purge_buffers()

    def _get_serial_number(self):
        """
        Retrieves the FTDI device serial number.

        :returns: string containing the device serial number
        """
        return usb.util.get_string(self._device.usb_dev, 64,
                                   self._device.usb_dev.iSerialNumber)

    class DetectThread(threading.Thread):
        """
        Thread that handles detection of added/removed devices.
        """
        on_attached = event.Event(
            "This event is called when an `AD2USB`_ device has been detected.\n\n**Callback definition:** def callback(thread, device*"
        )
        on_detached = event.Event(
            "This event is called when an `AD2USB`_ device has been removed.\n\n**Callback definition:** def callback(thread, device*"
        )

        def __init__(self, on_attached=None, on_detached=None):
            """
            Constructor

            :param on_attached: Function to call when a device is attached  **Callback definition:** *def callback(thread, device)*
            :type on_attached: function
            :param on_detached: Function to call when a device is detached  **Callback definition:** *def callback(thread, device)*
            :type on_detached: function
            """
            threading.Thread.__init__(self)

            if on_attached:
                self.on_attached += on_attached

            if on_detached:
                self.on_detached += on_detached

            self._running = False

        def stop(self):
            """
            Stops the thread.
            """
            self._running = False

        def run(self):
            """
            The actual detection process.
            """
            self._running = True

            last_devices = set()

            while self._running:
                try:
                    current_devices = set(USBDevice.find_all())

                    for dev in current_devices.difference(last_devices):
                        self.on_attached(device=dev)

                    for dev in last_devices.difference(current_devices):
                        self.on_detached(device=dev)

                    last_devices = current_devices

                except CommError:
                    pass

                time.sleep(0.25)
예제 #14
0
 def __init__(self, idVendor, idProduct):
     self.vendor = idVendor
     self.product = idProduct
     self.f = Ftdi()
예제 #15
0
파일: ftdi.py 프로젝트: greyseason/pyftdi
 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()
예제 #16
0
def burn(firmware_file):
    global f
    f = Ftdi()
    try:
        f.open_mpsse(0x0403,
                     0x6010,
                     description="HiSPARC III Master",
                     interface=1,
                     initial=1,
                     direction=0b11)
    except (FtdiError, usb.USBError):
        print "RESET"
        usb.util.dispose_resources(f.usb_dev)
        f.open_mpsse(0x0403,
                     0x6010,
                     description="HiSPARC III Master",
                     interface=1,
                     initial=1,
                     direction=0b11)

    f.write_data([Ftdi.TCK_DIVISOR, 0, 0])
    f.write_data([Ftdi.DISABLE_CLK_DIV5])

    print_low_bits(f)

    print_high_bits(f)
    f.write_data([Ftdi.SET_BITS_HIGH, 0, 1])
    print_high_bits(f)
    f.write_data([Ftdi.SET_BITS_HIGH, 1, 1])
    print_high_bits(f)

    BUFSIZE = 64 * 1024

    with open(os.path.expanduser(firmware_file), 'rb') as file:
        while True:
            xbuf = file.read(BUFSIZE)
            if not xbuf:
                break

            LENGTH = len(xbuf) - 1
            LENGTH_L = LENGTH & 0xff
            LENGTH_H = LENGTH >> 8 & 0xff
            send_buf = [Ftdi.WRITE_BYTES_PVE_LSB
                        ] + [LENGTH_L, LENGTH_H] + [ord(u) for u in xbuf]
            f.write_data(send_buf)

    #for i in range(10):
    #    print_high_bits(f)
    #    f.write_data([0x8e, 0])

    print_high_bits(f)
    print_low_bits(f)
예제 #17
0
	def __init__(self, idVendor, idProduct):
		self.vendor = idVendor
		self.product = idProduct
		self.f = Ftdi()
예제 #18
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
예제 #19
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()
        #    print "vid: %s, pid: %s" % (str(hex(idVendor)), str(hex(idProduct)))
        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)
예제 #20
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()
예제 #21
0
파일: jtag.py 프로젝트: Tfou57/robomow
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"""
        curfreq = self._ftdi.open_mpsse(vendor, product, interface,
                                        direction=self.direction,
                                        #initial=0x0,
                                        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()
        #self._ftdi.validate_mpsse()

    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):
            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 AssertionError("Internal error")
        #self._ftdi.validate_mpsse()
        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"""
        data = ''
        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 = ord(data) >> 8-bit_count
        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"""
        data = ''
        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)
예제 #22
0
class USBDevice(Device):
    """
    `AD2USB`_ device utilizing PyFTDI's interface.
    """

    # Constants
    PRODUCT_IDS = ((0x0403, 0x6001), (0x0403, 0x6015))
    """List of Vendor and Product IDs used to recognize `AD2USB`_ devices."""
    DEFAULT_VENDOR_ID = PRODUCT_IDS[0][0]
    """Default Vendor ID used to recognize `AD2USB`_ devices."""
    DEFAULT_PRODUCT_ID = PRODUCT_IDS[0][1]
    """Default Product ID used to recognize `AD2USB`_ devices."""

    # Deprecated constants
    FTDI_VENDOR_ID = DEFAULT_VENDOR_ID
    """DEPRECATED: Vendor ID used to recognize `AD2USB`_ devices."""
    FTDI_PRODUCT_ID = DEFAULT_PRODUCT_ID
    """DEPRECATED: Product ID used to recognize `AD2USB`_ devices."""


    BAUDRATE = 115200
    """Default baudrate for `AD2USB`_ devices."""

    __devices = []
    __detect_thread = None

    @classmethod
    def find_all(cls, vid=None, pid=None):
        """
        Returns all FTDI devices matching our vendor and product IDs.

        :returns: list of devices
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        cls.__devices = []

        query = cls.PRODUCT_IDS
        if vid and pid:
            query = [(vid, pid)]

        try:
            cls.__devices = Ftdi.find_all(query, nocache=True)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)

        return cls.__devices

    @classmethod
    def devices(cls):
        """
        Returns a cached list of `AD2USB`_ devices located on the system.

        :returns: cached list of devices found
        """
        return cls.__devices

    @classmethod
    def find(cls, device=None):
        """
        Factory method that returns the requested :py:class:`USBDevice` device, or the
        first device.

        :param device: Tuple describing the USB device to open, as returned
                       by find_all().
        :type device: tuple

        :returns: :py:class:`USBDevice` object utilizing the specified device
        :raises: :py:class:`~alarmdecoder.util.NoDeviceError`
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        cls.find_all()

        if len(cls.__devices) == 0:
            raise NoDeviceError('No AD2USB devices present.')

        if device is None:
            device = cls.__devices[0]

        vendor, product, sernum, ifcount, description = device

        return USBDevice(interface=sernum, vid=vendor, pid=product)

    @classmethod
    def start_detection(cls, on_attached=None, on_detached=None):
        """
        Starts the device detection thread.

        :param on_attached: function to be called when a device is attached  **Callback definition:** *def callback(thread, device)*
        :type on_attached: function
        :param on_detached: function to be called when a device is detached  **Callback definition:** *def callback(thread, device)*

        :type on_detached: function
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        cls.__detect_thread = USBDevice.DetectThread(on_attached, on_detached)

        try:
            cls.find_all()
        except CommError:
            pass

        cls.__detect_thread.start()

    @classmethod
    def stop_detection(cls):
        """
        Stops the device detection thread.
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        try:
            cls.__detect_thread.stop()

        except Exception:
            pass

    @property
    def interface(self):
        """
        Retrieves the interface used to connect to the device.

        :returns: the interface used to connect to the device
        """
        return self._interface

    @interface.setter
    def interface(self, value):
        """
        Sets the interface used to connect to the device.

        :param value: may specify either the serial number or the device index
        :type value: string or int
        """
        self._interface = value
        if isinstance(value, int):
            self._device_number = value
        else:
            self._serial_number = value

    @property
    def serial_number(self):
        """
        Retrieves the serial number of the device.

        :returns: serial number of the device
        """

        return self._serial_number

    @serial_number.setter
    def serial_number(self, value):
        """
        Sets the serial number of the device.

        :param value: serial number of the device
        :type value: string
        """
        self._serial_number = value

    @property
    def description(self):
        """
        Retrieves the description of the device.

        :returns: description of the device
        """
        return self._description

    @description.setter
    def description(self, value):
        """
        Sets the description of the device.

        :param value: description of the device
        :type value: string
        """
        self._description = value

    def __init__(self, interface=0, vid=None, pid=None):
        """
        Constructor

        :param interface: May specify either the serial number or the device
                          index.
        :type interface: string or int
        """
        if not have_pyftdi:
            raise ImportError('The USBDevice class has been disabled due to missing requirement: pyftdi or pyusb.')

        Device.__init__(self)

        self._device = Ftdi()

        self._interface = 0
        self._device_number = 0
        self._serial_number = None

        self._vendor_id = USBDevice.DEFAULT_VENDOR_ID
        if vid:
            self._vendor_id = vid

        self._product_id = USBDevice.DEFAULT_PRODUCT_ID
        if pid:
            self._product_id = pid

        self._endpoint = 0
        self._description = None

        self.interface = interface

    def open(self, baudrate=BAUDRATE, no_reader_thread=False):
        """
        Opens the device.

        :param baudrate: baudrate to use
        :type baudrate: int
        :param no_reader_thread: whether or not to automatically start the
                                 reader thread.
        :type no_reader_thread: bool

        :raises: :py:class:`~alarmdecoder.util.NoDeviceError`
        """
        # Set up defaults
        if baudrate is None:
            baudrate = USBDevice.BAUDRATE

        self._read_thread = Device.ReadThread(self)

        # Open the device and start up the thread.
        try:
            self._device.open(self._vendor_id,
                              self._product_id,
                              self._endpoint,
                              self._device_number,
                              self._serial_number,
                              self._description)

            self._device.set_baudrate(baudrate)

            if not self._serial_number:
                self._serial_number = self._get_serial_number()

            self._id = self._serial_number

        except (usb.core.USBError, FtdiError) as err:
            raise NoDeviceError('Error opening device: {0}'.format(str(err)), err)

        except KeyError as err:
            raise NoDeviceError('Unsupported device. ({0:04x}:{1:04x})  You probably need a newer version of pyftdi.'.format(err[0][0], err[0][1]))

        else:
            self._running = True
            self.on_open()

            if not no_reader_thread:
                self._read_thread.start()

        return self

    def close(self):
        """
        Closes the device.
        """
        try:
            Device.close(self)

            # HACK: Probably should fork pyftdi and make this call in .close()
            self._device.usb_dev.attach_kernel_driver(self._device_number)

        except Exception:
            pass

    def fileno(self):
        """
        File number not supported for USB devices.
    
        :raises: NotImplementedError
        """
        raise NotImplementedError('USB devices do not support fileno()')

    def write(self, data):
        """
        Writes data to the device.

        :param data: data to write
        :type data: string

        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        try:
            self._device.write_data(data)

            self.on_write(data=data)

        except FtdiError as err:
            raise CommError('Error writing to device: {0}'.format(str(err)), err)

    def read(self):
        """
        Reads a single character from the device.

        :returns: character read from the device
        :raises: :py:class:`~alarmdecoder.util.CommError`
        """
        ret = None

        try:
            ret = self._device.read_data(1)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error reading from device: {0}'.format(str(err)), err)

        return ret

    def read_line(self, timeout=0.0, purge_buffer=False):
        """
        Reads a line from the device.

        :param timeout: read timeout
        :type timeout: float
        :param purge_buffer: Indicates whether to purge the buffer prior to
                             reading.
        :type purge_buffer: bool

        :returns: line that was read
        :raises: :py:class:`~alarmdecoder.util.CommError`, :py:class:`~alarmdecoder.util.TimeoutError`
        """

        def timeout_event():
            """Handles read timeout event"""
            timeout_event.reading = False
        timeout_event.reading = True

        if purge_buffer:
            self._buffer = b''

        got_line, ret = False, None

        timer = threading.Timer(timeout, timeout_event)
        if timeout > 0:
            timer.start()

        try:
            while timeout_event.reading:
                buf = self._device.read_data(1)

                if buf != b'':
                    ub = bytes_hack(buf)

                    self._buffer += ub

                    if ub == b"\n":
                        self._buffer = self._buffer.rstrip(b"\r\n")

                        if len(self._buffer) > 0:
                            got_line = True
                            break
                else:
                    time.sleep(0.01)

        except (usb.core.USBError, FtdiError) as err:
            raise CommError('Error reading from device: {0}'.format(str(err)), err)

        else:
            if got_line:
                ret, self._buffer = self._buffer, b''

                self.on_read(data=ret)

            else:
                raise TimeoutError('Timeout while waiting for line terminator.')

        finally:
            timer.cancel()

        return ret

    def purge(self):
        """
        Purges read/write buffers.
        """
        self._device.purge_buffers()

    def _get_serial_number(self):
        """
        Retrieves the FTDI device serial number.

        :returns: string containing the device serial number
        """
        return usb.util.get_string(self._device.usb_dev, 64, self._device.usb_dev.iSerialNumber)

    class DetectThread(threading.Thread):
        """
        Thread that handles detection of added/removed devices.
        """
        on_attached = event.Event("This event is called when an `AD2USB`_ device has been detected.\n\n**Callback definition:** def callback(thread, device*")
        on_detached = event.Event("This event is called when an `AD2USB`_ device has been removed.\n\n**Callback definition:** def callback(thread, device*")

        def __init__(self, on_attached=None, on_detached=None):
            """
            Constructor

            :param on_attached: Function to call when a device is attached  **Callback definition:** *def callback(thread, device)*
            :type on_attached: function
            :param on_detached: Function to call when a device is detached  **Callback definition:** *def callback(thread, device)*
            :type on_detached: function
            """
            threading.Thread.__init__(self)

            if on_attached:
                self.on_attached += on_attached

            if on_detached:
                self.on_detached += on_detached

            self._running = False

        def stop(self):
            """
            Stops the thread.
            """
            self._running = False

        def run(self):
            """
            The actual detection process.
            """
            self._running = True

            last_devices = set()

            while self._running:
                try:
                    current_devices = set(USBDevice.find_all())

                    for dev in current_devices.difference(last_devices):
                        self.on_attached(device=dev)

                    for dev in last_devices.difference(current_devices):
                        self.on_detached(device=dev)

                    last_devices = current_devices

                except CommError:
                    pass

                time.sleep(0.25)
예제 #23
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()
예제 #24
0
파일: jtag.py 프로젝트: greyseason/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"""
        curfreq = self._ftdi.open_mpsse(
            vendor,
            product,
            interface,
            direction=self.direction,
            #initial=0x0,
            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()
        #self._ftdi.validate_mpsse()

    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 AssertionError("Internal error")
        #self._ftdi.validate_mpsse()
        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"""
        data = ''
        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 = ord(data) >> 8 - bit_count
        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"""
        data = ''
        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.fromstring(out)
        self._stack_cmd(cmd)
예제 #25
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
예제 #26
0
파일: spi.py 프로젝트: greyseason/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):
        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()
예제 #27
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')
예제 #28
0
파일: ftdi.py 프로젝트: Tommos0/ptrdaq
 def find_all():
     devices = Ftdi.find_all([(FTDI_VENDOR_ID, FTDI_PRODUCT_ID)])
     return [(serial_str, description) for
             vendor_id, product_id, serial_str, num_interfaces,
             description in devices]
예제 #29
0
파일: spi.py 프로젝트: etihwnad/pyftdi
class SpiController(object):
    """SPI master"""

    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):
        """Instanciate a SpiController.
           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.
           cs_count is the number of /CS lines (one per device to drive on the
           SPI bus)
        """
        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,
            loopback=False):
        """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,
                                  loopback=loopback)

    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()
예제 #30
0
파일: burn.py 프로젝트: Tommos0/ptrdaq
def burn(firmware_file):
    global f
    f = Ftdi()
    try:
        f.open_mpsse(0x0403, 0x6010, description="HiSPARC III Master",
                     interface=1, initial=1, direction=0b11)
    except (FtdiError, usb.USBError):
        print "RESET"
        usb.util.dispose_resources(f.usb_dev)
        f.open_mpsse(0x0403, 0x6010, description="HiSPARC III Master",
                     interface=1, initial=1, direction=0b11)

    f.write_data([Ftdi.TCK_DIVISOR, 0, 0])
    f.write_data([Ftdi.DISABLE_CLK_DIV5])

    print_low_bits(f)

    print_high_bits(f)
    f.write_data([Ftdi.SET_BITS_HIGH, 0, 1])
    print_high_bits(f)
    f.write_data([Ftdi.SET_BITS_HIGH, 1, 1])
    print_high_bits(f)

    BUFSIZE = 64 * 1024

    with open(os.path.expanduser(firmware_file), 'rb') as file:
        while True:
            xbuf = file.read(BUFSIZE)
            if not xbuf:
                break
      
            LENGTH = len(xbuf) - 1
            LENGTH_L = LENGTH & 0xff
            LENGTH_H = LENGTH >> 8 & 0xff
            send_buf = [Ftdi.WRITE_BYTES_PVE_LSB] + [LENGTH_L, LENGTH_H] + [ord(u) for u in xbuf]
            f.write_data(send_buf)

    #for i in range(10):
    #    print_high_bits(f)
    #    f.write_data([0x8e, 0])

    print_high_bits(f)
    print_low_bits(f)
예제 #31
0
파일: ftdi.py 프로젝트: etihwnad/pyftdi
    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()
예제 #32
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()
#    print "vid: %s, pid: %s" % (str(hex(idVendor)), str(hex(idProduct)))
    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)
예제 #33
0
class Dionysus(Olympus):
  """Dionysus

  Concrete Class that implements Dionysus specific communication functions
  """

  def __init__(self, idVendor=0x0403, idProduct=0x8530, debug = False):
    Olympus.__init__(self, debug)
    self.vendor = idVendor
    self.product = idProduct
    self.dev = Ftdi()
    self._open_dev()

    self.name = "Dionysus"

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

  def _open_dev(self):
    """_open_dev
    
    Open an FTDI communication channel

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      Exception
    """
    frequency = 30.0E6
#Latency can go down t 2 but when set there is a small chance that there is a crash
    latency = 4
    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')
    self.dev.purge_buffers()


  def read(self, device_id, address, length = 1, mem_device = False):
    """read

    read data from the Olympus image

    Args:
      device_id: Device identification number, found in the DRT
      address: Address of the register/memory to read
      mem_device: True if the device is on the memory bus
      length: Number of 32 bit words to read from the FPGA

    Returns:
      A byte array containing the raw data returned from Olympus

    Raises:
      OlympusCommError
    """
    read_data = Array('B')

    write_data = Array('B', [0xCD, 0x02]) 
    if mem_device:
      if self.debug:
        print "memory device"
      write_data = Array ('B', [0xCD, 0x12])
  
    fmt_string = "%06X" % (length) 
    write_data.fromstring(fmt_string.decode('hex'))
    offset_string = "00"
    if not mem_device:
      offset_string = "%02X" % device_id

    write_data.fromstring(offset_string.decode('hex'))

    addr_string = "%06X" % address
    write_data.fromstring(addr_string.decode('hex'))
    if self.debug:
      print "data read string: " + str(write_data)

    self.dev.purge_buffers()
    self.dev.write_data(write_data)

    timeout = time.time() + self.read_timeout
    rsp = Array('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      if len(response) > 0:
        rsp = Array('B')
        rsp.fromstring(response)
        if rsp[0] == 0xDC:
          if self.debug:
            print "Got a response"  
          break

    if len(rsp) > 0:
      if rsp[0] != 0xDC:
        if self.debug:
          print "Response not found"  
        raise OlympusCommError("Did not find identification byte (0xDC): %s" % str(rsp))
    else:
      if self.debug:      
        print "No Response found"
      raise OlympusCommError("Timeout while waiting for a response")

    #I need to watch out for the modem status bytes
    read_count = 0
    response = Array('B')
    rsp = Array('B')
    timeout = time.time() + self.read_timeout

    while (time.time() < timeout) and (read_count < (length * 4 + 8)):
      response = self.dev.read_data((length * 4 + 8 ) - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      #print "temp: %s", str(temp)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)
    
    if self.debug:
      print "read length = %d, total length = %d" % (len(rsp), (length * 4 + 8))
      print "time left on timeout: %d" % (timeout - time.time())

    if self.debug:
      print "response length: " + str(length * 4 + 8)
      print "response status:\n\t" + str(rsp[:8])
      print "response data:\n" + str(rsp[8:])

    return rsp[8:]
    

  def write(self, device_id, address, data=None, mem_device = False):
    """write

    Write data to an Olympus image

    Args:
      device_id: Device identification number, found in the DRT
      address: Address of the register/memory to read
      mem_device: True if the device is on the memory bus
      data: Array of raw bytes to send to the device

    Returns:
      Nothing

    Raises:
      OlympusCommError
    """
    length = len(data) / 4

    # ID 01 NN NN NN OO AA AA AA DD DD DD DD
      # ID = ID BYTE (0xCD)
      # 01 = Write Command
      # NN = Size of write (3 bytes)
      # OO = Offset of device
      # AA = Address (4 bytes)
      # DD = Data (4 bytes)

    #create an array with the identification byte (0xCD)
    #and code for write (0x01)

    data_out = Array('B', [0xCD, 0x01]) 
    if mem_device:
      if self.debug:
        print "memory device"
      data_out = Array ('B', [0xCD, 0x11])
    
    """
    print "write command:\n\t" + str(data_out[:9])
    for i in range (0, len(data_out)):
      print str(hex(data_out[i])) + ", ",
    print " "
    """

 

    #append the length into the frist 32 bits
    fmt_string = "%06X" % (length) 
    data_out.fromstring(fmt_string.decode('hex'))
    offset_string = "00"
    if not mem_device:
      offset_string = "%02X" % device_id
    data_out.fromstring(offset_string.decode('hex'))
    addr_string = "%06X" % address
    data_out.fromstring(addr_string.decode('hex'))
    
    data_out.extend(data)

    """
    #if (self.debug):
    print "data write string:\n"
    print "write command:\n\t" + str(data_out[:9])
    for i in range (0, 9):
      print str(hex(data_out[i])) + ", ",
    print " "
    """


    #print "write data:\n" + str(data_out[9:])

    #avoid the akward stale bug
    self.dev.purge_buffers()

    self.dev.write_data(data_out)
    rsp = Array('B')

    timeout = time.time() + self.read_timeout
    while time.time() < timeout:
      response = self.dev.read_data(1)
      if len(response) > 0:
        rsp = Array('B')
        rsp.fromstring(response)
        if rsp[0] == 0xDC:
          if self.debug:
            print "Got a response"  
          break

    if (len(rsp) > 0):
      if rsp[0] != 0xDC:
        if self.debug:
          print "Response not found"  
        raise OlympusCommError("Did not find identification byte (0xDC): %s" % str(rsp))

    else:
      if self.debug:
        print "No Response"
      raise OlympusCommError("Timeout while waiting for a response")

    response = self.dev.read_data(8)
    rsp = Array('B')
    rsp.fromstring(response)

    if self.debug:
      print "Response: " + str(rsp)

  def ping(self):
    """ping

    Pings the Olympus image

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      OlympusCommError
    """
    data = Array('B')
    data.extend([0XCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
    if self.debug:
      print "Sending ping...",
    self.dev.write_data(data)
    rsp = Array('B')
    temp = Array('B')

    timeout = time.time() + self.read_timeout

    while time.time() < timeout:
      response = self.dev.read_data(5)
      if self.debug:
        print ".",
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        if self.debug:
          print "Got a response"  
          print "Response: %s" % str(temp)
        break

    if not 0xDC in rsp:
      if self.debug:
        print "ID byte not found in response"  
        print "temp: " + str(temp)
      raise OlympusCommError("Ping response did not contain ID: %s" % str(temp))

    index  = rsp.index(0xDC) + 1

    read_data = Array('B')
    read_data.extend(rsp[index:])
    num = 3 - index
    read_data.fromstring(self.dev.read_data(num))
    if self.debug:
      print "Success!"
    return


  def reset(self):
    """reset

    Software reset the Olympus FPGA Master, this may not actually reset the
    entire FPGA image

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      OlympusCommError: A failure of communication is detected
    """
    data = Array('B')
    data.extend([0XCD, 0x03, 0x00, 0x00, 0x00]);
    if self.debug:
      print "Sending reset..."
    self.dev.purge_buffers()
    self.dev.write_data(data)

  def dump_core(self):
    """dump_core

    reads the state of the wishbone master prior to a reset, useful for
    debugging

    Args:
      Nothing

    Returns:
      Array of 32-bit values to be parsed by core_analyzer

    Raises:
      AssertionError: This function must be overriden by a board specific
      implementation
      OlympusCommError: A failure of communication is detected
    """

    data = Array('B')
    data.extend([0xCD, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
    print "Sending core dump request..."

    self.dev.purge_buffers()
    self.dev.write_data(data)

    core_dump = Array('L')
    wait_time = 5
    timeout = time.time() + wait_time

    temp = Array ('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        print "Got a response"  
        break

    if not 0xDC in rsp:
      print "Response not found"  
      raise OlympusCommError("Response Not Found")

    rsp = Array('B')
    read_total = 4
    read_count = len(rsp)

    #get the number of items from the address
    timeout = time.time() + wait_time
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    print "Length of read: %d" % len(rsp)
    print "Data: %s" % str(rsp)
    count  = ( rsp[1] << 16 | rsp[2] << 8 | rsp[3]) * 4
    print "Number of core registers: %d" % (count / 4)

    #get the core dump data
    timeout = time.time() + wait_time
    read_total  = count
    read_count  = 0
    temp = Array ('B')
    rsp = Array('B')
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    print "Length read: %d" % (len(rsp) / 4)
    print "Data: %s" % str(rsp)
    core_data = Array('L')
    for i in range (0, count, 4):
      print "count: %d" % i
      core_data.append(rsp[i] << 24 | rsp[i + 1] << 16 | rsp[i + 2] << 8 | rsp[i + 3])
    
    #if self.debug:
    print "core data: " + str(core_data)

    return core_data



 

  def wait_for_interrupts(self, wait_time = 1):
    """wait_for_interrupts
    
    listen for interrupts for the specified amount of time

    Args:
      wait_time: the amount of time in seconds to wait for an interrupt

    Returns:
      True: Interrupts were detected
      False: No interrupts detected

    Raises:
      Nothing
    """
    timeout = time.time() + wait_time

    temp = Array ('B')
    while time.time() < timeout:
      response = self.dev.read_data(1)
      rsp = Array('B')
      rsp.fromstring(response)
      temp.extend(rsp)
      if 0xDC in rsp:
        if self.debug:
          print "Got a response"  
        break

    if not 0xDC in rsp:
      if self.debug:
        print "Response not found"  
      return False

    read_total = 9
    read_count = len(rsp)

    #print "read_count: %s" % str(rsp)
    while (time.time() < timeout) and (read_count < read_total):
      response = self.dev.read_data(read_total - read_count)
      temp  = Array('B')
      temp.fromstring(response)
      #print "temp: %s", str(temp)
      if (len(temp) > 0):
        rsp += temp
        read_count = len(rsp)

    #print "read_count: %s" % str(rsp)
   

    index  = rsp.index(0xDC) + 1

    read_data = Array('B')
    read_data.extend(rsp[index:])
    #print "read_data: " + str(rsp)

    self.interrupts = read_data[-4] << 24 | read_data[-3] << 16 | read_data[-2] << 8 | read_data[-1]
    
    if self.debug:
      print "interrupts: " + str(self.interrupts)
    return True


  def comm_debug(self):
    """comm_debug

    A function that the end user will probably not interract with
    This is here to simply debug a communication medium

    Args:
      Nothing

    Returns:
      Nothing

    Raises:
      Nothing
    """
    #self.dev.set_dtr_rts(True, True)
    #self.dev.set_dtr(False)
    print "CTS: " + str(self.dev.get_cts())
#    print "DSR: " + str(self.dev.get_dsr())
    s1 = self.dev.modem_status()
    print "S1: " + str(s1)
예제 #34
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')
예제 #35
0
 def find_all():
     devices = Ftdi.find_all([(FTDI_VENDOR_ID, FTDI_PRODUCT_ID)])
     return [(serial_str, description) for vendor_id, product_id,
             serial_str, num_interfaces, description in devices]