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
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))
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
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
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
def test_open_bitbang(self): """Check simple open/close BitBang sequence.""" ftdi = Ftdi() ftdi.open_bitbang_from_url('ftdi:///1') ftdi.close()
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))