#!/usr/bin/env python # (C) 2008 Jacob Joseph # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # 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 #enum ftdi_chip_type { TYPE_AM=0, TYPE_BM=1, TYPE_2232C=2 }; (fct_TYPE_AM, fct_TYPE_BM, fct_TYPE_2232C) = map(c_int, range(3)) #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)) #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)) #enum ftdi_bits_type { BITS_7=7, BITS_8=8 }; (fbt_BITS_7, fbt_BITS_8) = map(c_int, (7,8)) #enum ftdi_mpsse_mode { # BITMODE_RESET = 0x00, # BITMODE_BITBANG= 0x01, # BITMODE_MPSSE = 0x02, # BITMODE_SYNCBB = 0x04, # BITMODE_MCU = 0x08, # BITMODE_OPTO = 0x10 # }; (fmm_BITMODE_RESET, fmm_BITMODE_BITBANG, ffm_BITMODE_MPSEE, ffm_BITMODE_SYNCBB, ffm_BITMODE_MCU, ffm_BITMODE_OPTO) = ( 0x00, 0x01, 0x02, 0x04, 0x08, 0x10) #enum ftdi_interface { # INTERFACE_ANY = 0, # INTERFACE_A = 1, # INTERFACE_B = 2 #}; (fi_INTERFACE_ANY, fi_INTERFACE_A, fi_INTERFACE_B) = map(c_int, range(3)) # 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 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), # 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), ('error_str', c_char_p)] class ftdi(object): """A ctype interface to the libfdi driver.""" FT = None # FTDI shared library ftdic = None # context def __init__(self, description=None, serial=None): self.FT = CDLL("libftdi.so") self.ftdic = ftdi_context() self.init() self.usb_open(description=description, serial=serial) def close(self): self.usb_close() self.deinit() def init(self): ret = self.FT.ftdi_init(byref(self.ftdic)) print "init return:", ret if ret < 0: raise "Error calling init: couldn't allocate read buffer. Returned: %d" % ret return ret def deinit(self): self.FT.ftdi_deinit(byref(self.ftdic)) return def usb_open(self, vendor=0x0403, product=0x6001, description=None, serial=None): """Opens the device. If description and serial are not specified, open the first device found.""" ret = self.FT.ftdi_usb_open(byref(self.ftdic), vendor, product, description, serial) print "usb_open return:", ret if ret < 0: raise "Error calling usb_open: Returned: %d" % ret return ret def usb_close(self): "Opens the first device with a given vendor and product ids." ret = self.FT.ftdi_usb_close(byref(self.ftdic)) print "usb_close return:", ret if ret < 0: raise "Error calling usb_close: Returned: %d" % ret return ret def enable_bitbang(self, bitmask): """Enable bitbang mode. High/On value in the bitmask configures a line as an output.""" ret = self.FT.ftdi_enable_bitbang(byref(self.ftdic), c_ubyte(bitmask)) if ret < 0: raise "Error calling enable_bitbang: Returned: %d" % ret return ret def disable_bitbang(self): """Disable bitbang mode.""" ret = self.FT.ftdi_disable_bitbang(byref(self.ftdic)) if ret < 0: raise "Error calling disable_bitbang: Returned: %d" % ret 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_int * len(buf) cbuf = Arr( *buf) elif size is not None: cbuf = buf else: raise "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(byref(self.ftdic), byref(cbuf), size) if ret < 0: raise "Error calling write_data: Returned: %d" % ret return ret def read_pins(self): """Read pins""" pin_state = c_int() ret = self.FT.ftdi_read_pins(byref(self.ftdic), byref(pin_state)) return pin_state def set_baudrate(self, rate): ret = self.FT.ftdi_set_baudrate(byref(self.ftdic), rate) if ret < 0: raise "Error calling write_data: Returned: %d" % ret return ret def purge_buffers(self): ret = self.FT.ftdi_usb_purge_buffers(byref(self.ftdic)) if ret < 0: raise "Error calling purge_buffers: Returned: %d" % ret return ret def write_data_set_chunksize(self, chunksize): ret = self.FT.ftdi_write_data_set_chunksize(byref(self.ftdic), chunksize) if ret < 0: raise "Error calling write_data_set_chunksize: Returned: %d" % ret return ret def write_data_get_chunksize(self): chunksize = c_int() ret = self.FT.ftdi_write_data_get_chunksize(byref(self.ftdic), byref(chunksize)) if ret < 0: raise "Error calling write_data_get_chunksize: Returned: %d" % ret return chunksize def set_latency_timer(self, latency): ret = self.FT.ftdi_set_latency_timer(byref(self.ftdic), latency) if ret < 0: raise "Error calling set_latency_timer: Returned: %d" % ret return ret def get_latency_timer(self): latency = c_int() ret = self.FT.ftdi_get_latency_timer(byref(self.ftdic), byref(latency)) if ret < 0: raise "Error calling get_latency_timer: Returned: %d" % ret 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()