#!/usr/bin/env python # Jacob Joseph # 2008-02-22 # An initial attempt to use the libftdi library for the FTDI usb # interfaces. (see # http://www.intra2net.com/de/produkte/opensource/ftdi/) # This use of ctypes is modeled after an FTD2xx driver posted in a # forum by Jonathan Roadley-Battin from ctypes import * # Enum types aren't directly supported # FTDI chip type #enum ftdi_chip_type { TYPE_AM=0, TYPE_BM=1, TYPE_2232C=2, TYPE_R=3, TYPE_2232H=4, TYPE_4232H=5 }; (fct_TYPE_AM, fct_TYPE_BM, fct_TYPE_2232C, fct_TYPE_R, fct_TYPE_2232H, fct_TYPE_4232H) = map(c_int, range(6)) # Parity mode for ftdi_set_line_property() #enum ftdi_parity_type { NONE=0, ODD=1, EVEN=2, MARK=3, SPACE=4 }; (fpt_NONE, fpt_ODD, fpt_EVEN, fpt_MARK, fpt_SPACE) = map(c_int, range(5)) # Number of stop bits for ftdi_set_line_property() #enum ftdi_stopbits_type { STOP_BIT_1=0, STOP_BIT_15=1, STOP_BIT_2=2 }; (fst_STOP_BIT_1, fst_STOP_BIT_15, fst_STOP_BIT_2) = map(c_int, range(3)) # Number of bits for ftdi_set_line_property() #enum ftdi_bits_type { BITS_7=7, BITS_8=8 }; (fbt_BITS_7, fbt_BITS_8) = map(c_int, (7,8)) # Break type for ftdi_set_line_property2() #enum ftdi_break_type { BREAK_OFF=0, BREAK_ON=1 }; (fbt_BREAK_OFF, fbt_BREAK_ON) = map(c_int, (0,1)); # MPSSE bitbang modes BITMODE_RESET = 0x00 # switch off bitbang mode, back to regular serial/FIFO BITMODE_BITBANG= 0x01 # classical asynchronous bitbang mode, introduced with B-type chips BITMODE_MPSSE = 0x02 # MPSSE mode, available on 2232x chips BITMODE_SYNCBB = 0x04 # synchronous bitbang mode, available on 2232x and R-type chips BITMODE_MCU = 0x08 # MCU Host Bus Emulation mode, available on 2232x chips # CPU-style fifo mode gets set via EEPROM BITMODE_OPTO = 0x10 # Fast Opto-Isolated Serial Interface Mode, available on 2232x chips BITMODE_CBUS = 0x20 # Bitbang on CBUS pins of R-type chips, configure in EEPROM before BITMODE_SYNCFF = 0x40 # Single Channel Synchronous FIFO mode, available on 2232H chips #enum ftdi_interface { # INTERFACE_ANY = 0, # INTERFACE_A = 1, # INTERFACE_B = 2 #}; (fi_INTERFACE_ANY, fi_INTERFACE_A, fi_INTERFACE_B, fi_INTERFACE_C, fi_INTERFACE_D) = map(c_int, range(5)) # Shifting commands IN MPSSE Mode MPSSE_WRITE_NEG = 0x01 # Write TDI/DO on negative TCK/SK edge MPSSE_BITMODE = 0x02 # Write bits, not bytes MPSSE_READ_NEG = 0x04 # Sample TDO/DI on negative TCK/SK edge MPSSE_LSB = 0x08 # LSB first MPSSE_DO_WRITE = 0x10 # Write TDI/DO MPSSE_DO_READ = 0x20 # Read TDO/DI MPSSE_WRITE_TMS = 0x40 # Write TMS/CS # FTDI MPSSE commands SET_BITS_LOW = 0x80 SET_BITS_HIGH = 0x82 GET_BITS_LOW = 0x81 GET_BITS_HIGH = 0x83 LOOPBACK_START = 0x84 LOOPBACK_END = 0x85 TCK_DIVISOR = 0x86 #/* Value Low */ #/* Value HIGH */ /*rate is 12000000/((1+value)*2) */ #define DIV_VALUE(rate) (rate > 6000000)?0:((6000000/rate -1) > 0xffff)? 0xffff: (6000000/rate -1) # Commands in MPSSE and Host Emulation Mode SEND_IMMEDIATE = 0x87 WAIT_ON_HIGH = 0x88 WAIT_ON_LOW = 0x89 # Commands in Host Emulation Mode READ_SHORT = 0x90 READ_EXTENDED = 0x91 WRITE_SHORT = 0x92 WRITE_EXTENDED = 0x93 # Definitions for flow control SIO_RESET = 0 # Reset the port SIO_MODEM_CTRL = 1 # Set the modem control register SIO_SET_FLOW_CTRL= 2 # Set flow control register SIO_SET_BAUD_RATE= 3 # Set baud rate SIO_SET_DATA = 4 # Set the data characteristics of the port class usb_dev_handle(Structure): pass # Pointers c_ubyte_p = POINTER(c_ubyte) usb_dev_handle_p = POINTER(usb_dev_handle) class ftdi_context(Structure): _fields_ = [ # USB specific ('usb_dev', usb_dev_handle_p), # struct usb_dev_handle *usb_dev; ('usb_read_timeout', c_int), ('usb_write_timeout', c_int), # FTDI specific ('type', c_int), # enum ftdi_chip_type type; ('baudrate', c_int), ('bitbang_enabled', c_ubyte), ('readbuffer', c_ubyte_p), ('readbuffer_offset', c_uint), ('readbuffer_remaining', c_uint), ('readbuffer_chunksize', c_uint), ('writebuffer_chunksize', c_uint), ('max_packet_size', c_uint), # FTDI FT2232C requirements ('interface', c_int), ('index', c_int), ('in_ep', c_int), ('out_ep', c_int), # 1: (default) Normal bitbang mode, 2: FT2232C SPI bitbang mode ('bitbang_mode', c_ubyte), ('eeprom_size', c_int), ('error_str', c_char_p), ('async_usb_buffer', c_char_p), ('async_usb_buffer_size', c_uint) ] class ftdi(object): """A ctype interface to the libfdi driver.""" FT = None # FTDI shared library context = None # context ftdic = None # context. C reference def __init__(self, description=None, serial=None): self.FT = CDLL("libftdi.so") self.set_return_types() self.context = ftdi_context() self.ftdic = byref( self.context) self.open() # be sure bitbang mode is disabled self.set_bitmode( 0xFF, BITMODE_RESET) def set_return_types(self): """set ctypes if not ints""" self.FT.ftdi_get_error_string.restype = c_char_p return def __del__(self): self.close() def get_error_string(self): return self.FT.ftdi_get_error_string( self.ftdic) def open(self, vendor=0x0403, product=0x6001): ret = self.FT.ftdi_init(self.ftdic) assert ret >= 0, "ftdi_init() failed: %d (%s)" % ( ret, self.get_error_string()) ret = self.FT.ftdi_usb_open(self.ftdic, vendor, product) assert ret >= 0, "ftdi_usb_open() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def close(self): if self.ftdic is None: return None ret = self.FT.ftdi_usb_close(self.ftdic) assert ret >= 0, "ftdi_usb_close() failed: %d (%s)" % ( ret, self.get_error_string()) self.FT.ftdi_deinit(self.ftdic) #self.FT.ftdi_free( self.ftdic) #assert ret >= 0, "ftdi_deinit() failed: %d (%s)" % ( # ret, self.get_error_string()) self.FT = None self.context = None self.ftdic = None return ret def set_bitmode( self, bitmask, mode): ret = self.FT.ftdi_set_bitmode( self.ftdic, bitmask, mode) assert ret >= 0, "ftdi_set_bitmode() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def disable_bitbang(self): """Disable bitbang mode.""" ret = self.FT.ftdi_disable_bitbang(self.ftdic) assert ret >= 0, "ftdi_disable_bitbang() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def write_data(self, buf, size=None): """Writes data (bytes) in chunks to the chip.""" # passed a python array if type(buf) is list: size = len(buf) Arr = c_ubyte * len(buf) cbuf = Arr( *buf) elif size is not None: cbuf = buf else: assert False, "write_data: must specify size if buf is not a python list" #from IPython.Shell import IPShellEmbed #ipsh = IPShellEmbed() #ipsh("ready to write data") ret = self.FT.ftdi_write_data(self.ftdic, byref(cbuf), size) assert ret >= 0, "ftdi_write_data() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def read_data(self): """Read data from the device until there is no more, in 4096-byte chunks""" size = 4096 Arr = c_ubyte * size cbuf = Arr() ret = [] while True: nbytes = self.FT.ftdi_read_data( self.ftdic, byref(cbuf), size) assert nbytes >= 0, "ftdi_read_data() failed: %d (%s)" % ( nbytes, self.get_error_string()) ret += cbuf[:nbytes] if nbytes < size: break print "read %d bytes: %s" % (len(ret), ret) return ret def read_pins(self): """Read pins""" pin_state = c_int() ret = self.FT.ftdi_read_pins(self.ftdic, byref(pin_state)) return pin_state def set_baudrate(self, rate): ret = self.FT.ftdi_set_baudrate(self.ftdic, rate) assert ret >= 0, "ftdi_set_baudrate() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def purge_buffers(self): ret = self.FT.ftdi_usb_purge_buffers(self.ftdic) assert ret >= 0, "ftdi_usb_purge_buffers() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def write_data_set_chunksize(self, chunksize): ret = self.FT.ftdi_write_data_set_chunksize(self.ftdic, chunksize) assert ret >= 0, "ftdi_write_data_set_chunksize() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def write_data_get_chunksize(self): chunksize = c_int() ret = self.FT.ftdi_write_data_get_chunksize(self.ftdic, byref(chunksize)) assert ret >= 0, "ftdi_write_data_get_chunksize() failed: %d (%s)" % ( ret, self.get_error_string()) return chunksize def set_latency_timer(self, latency): ret = self.FT.ftdi_set_latency_timer(self.ftdic, latency) assert ret >= 0, "ftdi_set_latency_timer() failed: %d (%s)" % ( ret, self.get_error_string()) return ret def get_latency_timer(self): latency = c_int() ret = self.FT.ftdi_get_latency_timer(self.ftdic, byref(latency)) assert ret >= 0, "ftdi_get_latency_timer() failed: %d (%s)" % ( ret, self.get_error_string()) return latency if __name__ == "__main__": ft = ftdi() #ft.enable_bitbang(0xFF) #Arr = c_int * 1000000 #buf = Arr(*([0xFF, 0x00] * 500000)) #time.time() #ft.write_data(buf, 1000000) #time.time()