Пример #1
0
 def open_from_url(self, url, direction, **kwargs):
     """
     """
     for k in ('direction',):
         if k in kwargs:
             del kwargs[k]
     try:
         ftdi = Ftdi()
         ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
         self._ftdi = ftdi
     except IOError as e:
         raise GpioException('Unable to open USB port: %s' % str(e))
     self._direction = direction
Пример #2
0
 def setUp(self):
     """Open a connection to the FTDI, defining which pins are configured as
        output and input"""
     # out_pins value of 0x00 means all inputs
     out_pins = 0x00
     try:
         ftdi = Ftdi()
         # If you REALLY muck things up, need to use this open_bitbang()
         # function directly and enter vendor and product ID:
         # ftdi.open_bitbang(vendor=0x0403, product=0x6011,
         #                   direction=out_pins)
         ftdi.open_bitbang_from_url(self.url, direction=out_pins)
         self.ftdi = ftdi
     except IOError as ex:
         raise IOError('Unable to open USB port: %s' % str(ex))
Пример #3
0
    def configure(self, url, direction=0, **kwargs):
        """Open a new interface to the specified FTDI device in bitbang mode.

           :param str url: a FTDI URL selector
           :param int direction: a bitfield specifying the FTDI GPIO direction,
                where high level defines an output, and low level defines an
                input
        """
        for k in ('direction',):
            if k in kwargs:
                del kwargs[k]
        try:
            ftdi = Ftdi()
            ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
            self._ftdi = ftdi
        except IOError as ex:
            raise GpioException('Unable to open USB port: %s' % str(ex))
        self._direction = direction
Пример #4
0
    def configure(self, url, direction=0, **kwargs):
        """Open a new interface to the specified FTDI device in bitbang mode.

           :param str url: a FTDI URL selector
           :param int direction: a bitfield specifying the FTDI GPIO direction,
                where high level defines an output, and low level defines an
                input
        """
        for k in ('direction', ):
            if k in kwargs:
                del kwargs[k]
        try:
            ftdi = Ftdi()
            ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
            self._ftdi = ftdi
        except IOError as e:
            raise GpioException('Unable to open USB port: %s' % str(e))
        self._direction = direction
Пример #5
0
    def configure(self, url, direction=0, **kwargs):
        """Open a new interface to the specified FTDI device in bitbang mode.

           :param str url: a FTDI URL selector
           :param int direction: a bitfield specifying the FTDI GPIO direction,
                where high level defines an output, and low level defines an
                input
        """
        for k in ('direction', ):
            if k in kwargs:
                del kwargs[k]
        try:
            ftdi = Ftdi()
            ftdi.open_bitbang_from_url(url, direction=direction, **kwargs)
            self._ftdi = ftdi
        except IOError as ex:
            raise GpioException('Unable to open USB port: %s' % str(ex))
        self._direction = direction

        with self._lock:
            if (self._ftdi.has_wide_port and self._ftdi.has_mpsse):
                # If this device supports the wide 16-bit GPIO port,
                # must open as MPSSE to access the 16-bits. So close
                # ftdi and re-open it as MPSSE.
                try:
                    self._ftdi.close()
                    ftdi = Ftdi()
                    ftdi.open_mpsse_from_url(url,
                                             direction=direction,
                                             **kwargs)
                    self._ftdi = ftdi
                except IOError as ex:
                    raise GpioException('Unable to open USB port: %s' %
                                        str(ex))

            self._wide_port = self._ftdi.has_wide_port

            gpio_width = self._wide_port and 16 or 8
            gpio_mask = (1 << gpio_width) - 1
            self._gpio_mask = gpio_mask
Пример #6
0
 def test_open_bitbang(self):
     """Check simple open/close BitBang sequence."""
     ftdi = Ftdi()
     ftdi.open_bitbang_from_url('ftdi:///1')
     ftdi.close()
Пример #7
0
class I2C:
    SCL = 1 << 0
    SDAO = 1 << 1
    SDAI = 1 << 2
    EN = 1 << 4
    RESET_B = 1 << 5
    max_clock_stretch = 100

    def __init__(self):
        self.dev = Ftdi()
        self._time = 0
        self._direction = 0

    def configure(self, url, **kwargs):
        self.dev.open_bitbang_from_url(url, **kwargs)
        return self

    def tick(self):
        self._time += 1

    def reset_switch(self):
        self.write(self.EN)
        self.tick()
        self.write(self.EN | self.RESET_B)
        self.tick()
        time.sleep(.01)

    def set_direction(self, direction):
        self._direction = direction
        self.dev.set_bitmode(direction, Ftdi.BITMODE_BITBANG)

    def write(self, data):
        self.dev.write_data(bytes([data]))

    def read(self):
        return self.dev.read_pins()

    def scl_oe(self, oe):
        d = (self._direction & ~self.SCL)
        if oe:
            d |= self.SCL
        self.set_direction(d)

    def sda_oe(self, oe):
        d = self._direction & ~self.SDAO
        if oe:
            d |= self.SDAO
        self.set_direction(d)

    def scl_i(self):
        return bool(self.read() & self.SCL)

    def sda_i(self):
        return bool(self.read() & self.SDAI)

    def clock_stretch(self):
        for i in range(self.max_clock_stretch):
            r = self.read()
            if r & self.SCL:
                return bool(r & self.SDAI)
        raise ValueError("SCL low exceeded clock stretch limit")

    def acquire(self):
        self.write(self.EN | self.RESET_B)  # RESET_B, EN, !SCL, !SDA
        self.set_direction(self.EN | self.RESET_B)  # enable USB-I2C
        self.tick()
        # self.reset_switch()
        time.sleep(.1)
        i = self.read()
        if not i & self.EN:
            raise ValueError("EN low despite enable")
        if not i & self.SCL:
            raise ValueError("SCL stuck low")
        if not i & self.SDAI:
            raise ValueError("SDAI stuck low")
        if not i & self.SDAO:
            raise ValueError("SDAO stuck low")
        return self

    def release(self):
        # self.reset_switch()
        self.set_direction(self.EN | self.RESET_B)
        self.write(self.RESET_B)
        self.tick()
        i = self.read()
        if i & self.EN:
            raise ValueError("EN high despite disable")
        if not i & self.SCL:
            raise ValueError("SCL low despite disable")
        if not i & self.SDAI:
            raise ValueError("SDAI low despite disable")
        if not i & self.SDAO:
            raise ValueError("SDAO low despite disable")

    def __enter__(self):
        self.acquire()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.release()

    def clear(self):
        self.tick()
        self.scl_oe(False)
        self.tick()
        self.sda_oe(False)
        self.tick()
        for i in range(9):
            if self.clock_stretch():
                break
            self.scl_oe(True)
            self.tick()
            self.scl_oe(False)
            self.tick()

    def start(self):
        logger.debug("S")
        assert self.scl_i()
        if not self.sda_i():
            raise ValueError("Arbitration lost")
        self.sda_oe(True)
        self.tick()
        self.scl_oe(True)
        # SCL low, SDA low

    def stop(self):
        logger.debug("P")
        # SCL low, SDA low
        self.tick()
        self.scl_oe(False)
        self.tick()
        self.clock_stretch()
        self.sda_oe(False)
        self.tick()
        if not self.sda_i():
            raise ValueError("Arbitration lost")

    def restart(self):
        logger.debug("R")
        # SCL low, SDA low
        self.sda_oe(False)
        self.tick()
        self.scl_oe(False)
        self.tick()
        assert self.clock_stretch()
        self.start()

    def write_data(self, data):
        for i in range(8):
            bit = bool(data & (1 << 7 - i))
            self.sda_oe(not bit)
            self.tick()
            self.scl_oe(False)
            self.tick()
            if self.clock_stretch() != bit:
                raise ValueError("Arbitration lost")
            self.scl_oe(True)
        # check ACK
        self.sda_oe(False)
        self.tick()
        self.scl_oe(False)
        self.tick()
        ack = not self.clock_stretch()
        self.scl_oe(True)
        self.sda_oe(True)
        # SCL low, SDA low
        logger.debug("W %#02x %s", data, "A" if ack else "N")
        return ack

    def read_data(self, ack=True):
        self.sda_oe(False)
        data = 0
        for i in range(8):
            self.tick()
            self.scl_oe(False)
            self.tick()
            if self.clock_stretch():
                data |= 1 << 7 - i
            self.scl_oe(True)
        # send ACK
        self.sda_oe(ack)
        self.tick()
        self.scl_oe(False)
        self.tick()
        if self.clock_stretch() == ack:
            raise ValueError("Arbitration lost")
        self.scl_oe(True)
        self.sda_oe(True)
        # SCL low, SDA low
        logger.debug("R %#02x %s", data, "A" if ack else "N")
        return data

    @contextmanager
    def xfer(self):
        self.start()
        try:
            yield
        finally:
            self.stop()

    def write_single(self, addr, data, ack=True):
        with self.xfer():
            if not self.write_data(addr << 1):
                raise I2CNACK("Address Write NACK", addr)
            if not self.write_data(data) and ack:
                raise I2CNACK("Data NACK", addr, data)

    def read_single(self, addr):
        with self.xfer():
            if not self.write_data((addr << 1) | 1):
                raise I2CNACK("Address Read NACK", addr)
            return self.read_data(ack=False)

    def write_many(self, addr, reg, data, ack=True):
        with self.xfer():
            if not self.write_data(addr << 1):
                raise I2CNACK("Address Write NACK", addr)
            if not self.write_data(reg):
                raise I2CNACK("Reg NACK", reg)
            for i, byte in enumerate(data):
                if not self.write_data(byte) and (ack or i < len(data) - 1):
                    raise I2CNACK("Data NACK", data)

    def read_many(self, addr, reg, length=1):
        with self.xfer():
            if not self.write_data(addr << 1):
                raise I2CNACK("Address Write NACK", addr)
            if not self.write_data(reg):
                raise I2CNACK("Reg NACK", reg)
            self.restart()
            if not self.write_data((addr << 1) | 1):
                raise I2CNACK("Address Read NACK", addr)
            return bytes(self.read_data(ack=i < length - 1)
                         for i in range(length))

    def read_stream(self, addr, length=1):
        with self.xfer():
            if not self.write_data((addr << 1) | 1):
                raise I2CNACK("Address Read NACK", addr)
            return bytes(self.read_data(ack=i < length - 1)
                         for i in range(length))

    def poll(self, addr, write=False):
        with self.xfer():
            return self.write_data((addr << 1) | int(not write))