mirror of
https://github.com/WangXuan95/FTDI-245fifo-interface.git
synced 2025-01-28 07:02:53 +08:00
284 lines
9.5 KiB
Python
284 lines
9.5 KiB
Python
#-*- coding:utf-8 -*-
|
|
# Python3
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
def open_ft_usb_device(device_type, device_name):
|
|
'''
|
|
open_ft_usb_device(str device_type, str device_name) -> USB-device object
|
|
function:
|
|
open an FTDI USB device
|
|
parameters :
|
|
device_type :
|
|
'FTX232H' : FT232H or FT2232H
|
|
'FT60X' : FT600 or FT601
|
|
device_name : the USB device's product name to be opened
|
|
for 'FTX232H', the chip's default device_name = 'USB <-> Serial Converter' unless the user has modified it.
|
|
for 'FT60X' , the chip's default device_name = 'FTDI SuperSpeed-FIFO Bridge' unless the user has modified it.
|
|
return:
|
|
a USB-device object
|
|
'''
|
|
|
|
b_device_name = bytes(device_name, encoding="ASCII")
|
|
|
|
if device_type == 'FT60X' : # search the FT60X device ################################################################################################
|
|
|
|
try:
|
|
import ftd3xx # import #
|
|
except:
|
|
return None, 'Failed to import ftd3xx'
|
|
|
|
for device_id in range(16):
|
|
|
|
if sys.platform == 'win32':
|
|
usb = ftd3xx.create(device_id, ftd3xx._ftd3xx_win32.FT_OPEN_BY_INDEX)
|
|
elif sys.platform == 'linux2':
|
|
usb = ftd3xx.create(device_id, ftd3xx._ftd3xx_linux.FT_OPEN_BY_INDEX)
|
|
|
|
if usb is None:
|
|
continue
|
|
|
|
if sys.platform == 'win32' and usb.getDriverVersion() < 0x01020006:
|
|
usb.close()
|
|
return None, 'Old D3XX driver version. Please update driver!'
|
|
|
|
if usb.getDeviceInfo()['Description'] != b_device_name:
|
|
usb.close()
|
|
continue
|
|
|
|
numChannel = [4, 2, 1, 0, 0][usb.getChipConfiguration().ChannelConfig]
|
|
if numChannel != 1:
|
|
usb.close()
|
|
return None, 'This %s is not in sync-245-fifo mode because number of channel is not 1 ! (numChannel=%d)' % (device_type, numChannel)
|
|
|
|
return usb, 'Successfully opened %s USB device: %s' % (device_type, device_name)
|
|
|
|
else: # search the FTX232H device ##############################################################################################
|
|
|
|
try:
|
|
import ftd2xx # import #
|
|
except:
|
|
return None, 'Failed to import ftd2xx'
|
|
|
|
for i in range(16):
|
|
|
|
try:
|
|
usb = ftd2xx.open(i)
|
|
except:
|
|
continue
|
|
|
|
if usb.description != b_device_name:
|
|
usb.close()
|
|
continue
|
|
|
|
usb.setBitMode(0xff, 0x40)
|
|
|
|
return usb, 'Successfully opened %s USB device: %s' % (device_type, device_name)
|
|
|
|
return None, 'Could not open %s USB device: %s' % (device_type, device_name)
|
|
|
|
|
|
|
|
|
|
|
|
class USB_FTX232H_FT60X_sync245mode():
|
|
|
|
def __init__(self, device_to_open_list = (('FTX232H', 'USB <-> Serial Converter' ),
|
|
('FT60X' , 'FTDI SuperSpeed-FIFO Bridge')) ):
|
|
'''
|
|
__init__(str device_type, str device_name) -> USB_FTX232H_FT60X_sync245mode object
|
|
function:
|
|
open FTDI USB device and return a USB_FTX232H_FT60X_sync245mode object
|
|
'''
|
|
|
|
for device_type, device_name in device_to_open_list:
|
|
|
|
usb, message = open_ft_usb_device(device_type, device_name)
|
|
print(message)
|
|
|
|
if not usb is None:
|
|
|
|
self.device_type = device_type
|
|
self.device_name = device_name
|
|
self._usb = usb
|
|
self._recv_timeout = 2000
|
|
self._send_timeout = 2000
|
|
|
|
self.set_recv_timeout(self._recv_timeout)
|
|
self.set_send_timeout(self._send_timeout)
|
|
|
|
if device_type == 'FT60X' :
|
|
if usb.getDeviceDescriptor().bcdUSB < 0x300:
|
|
print('Warning: Device is NOT connected using USB3.0 cable or port!')
|
|
self._chunk = 65536 * 16
|
|
else:
|
|
self._chunk = 65536
|
|
usb.setUSBParameters(self._chunk*4, self._chunk*4)
|
|
|
|
break
|
|
|
|
else:
|
|
raise Exception('Could not open USB device')
|
|
|
|
|
|
|
|
|
|
def close(self):
|
|
'''
|
|
close()
|
|
function:
|
|
close the FTDI USB device
|
|
'''
|
|
|
|
self._usb.close()
|
|
self._usb = None
|
|
|
|
|
|
|
|
|
|
def set_recv_timeout(self, timeout):
|
|
'''
|
|
set_recv_timeout(int timeout)
|
|
function:
|
|
set recv timeout
|
|
parameter:
|
|
int timeout : unit: ms
|
|
'''
|
|
|
|
self._recv_timeout = timeout
|
|
if self.device_type == 'FT60X' :
|
|
self._usb.setPipeTimeout(0x82, self._recv_timeout)
|
|
else:
|
|
self._usb.setTimeouts(self._recv_timeout, self._send_timeout)
|
|
|
|
|
|
|
|
|
|
def set_send_timeout(self, timeout):
|
|
'''
|
|
set_send_timeout(int timeout)
|
|
function:
|
|
set send timeout
|
|
parameter:
|
|
int timeout : unit: ms
|
|
'''
|
|
|
|
self._send_timeout = timeout
|
|
if self.device_type == 'FT60X' :
|
|
self._usb.setPipeTimeout(0x02, self._send_timeout)
|
|
else:
|
|
self._usb.setTimeouts(self._recv_timeout, self._send_timeout)
|
|
|
|
|
|
|
|
|
|
def send(self, data):
|
|
'''
|
|
send(bytes data) -> int actual_send_len
|
|
function:
|
|
send data
|
|
parameter:
|
|
bytes data : data to send
|
|
return:
|
|
int actual_send_len : actual sent byte count
|
|
if the device cannot accept so many data until timeout, actual_send_len < len(data)
|
|
'''
|
|
|
|
txlen = 0
|
|
|
|
for si in range(0, len(data), self._chunk):
|
|
ei = si + self._chunk
|
|
ei = min(ei, len(data))
|
|
|
|
chunk = data[si:ei]
|
|
|
|
if self.device_type == 'FT60X' :
|
|
txlen_once = self._usb.writePipe(0x02, chunk, len(chunk))
|
|
else:
|
|
txlen_once = self._usb.write(chunk)
|
|
|
|
txlen += txlen_once
|
|
|
|
if txlen_once < len(chunk):
|
|
break
|
|
|
|
return txlen
|
|
|
|
|
|
|
|
|
|
def recv(self, recv_len):
|
|
'''
|
|
recv(int recv_len) -> bytes data
|
|
function:
|
|
receive data
|
|
parameter:
|
|
int recv_len : data length to be received
|
|
return:
|
|
bytes data : received data bytes
|
|
if the device cannot send so many data until timeout, len(data) < recv_len
|
|
'''
|
|
|
|
data = b''
|
|
|
|
if self.device_type == 'FT60X' :
|
|
chunk = bytes(self._chunk)
|
|
|
|
zero_count = 0
|
|
si = 0
|
|
|
|
while si < recv_len :
|
|
ei = si + self._chunk
|
|
ei = min(ei, recv_len)
|
|
|
|
rxlen_once = self._usb.readPipe(0x82, chunk, ei-si) # try to read (ei-si) bytes
|
|
|
|
si += rxlen_once
|
|
|
|
if rxlen_once > 0 :
|
|
zero_count = 0
|
|
data += chunk[:rxlen_once]
|
|
else : # no any byte received
|
|
zero_count += 1
|
|
if zero_count >= 2 :
|
|
break
|
|
|
|
else:
|
|
for si in range(0, recv_len, self._chunk):
|
|
ei = si + self._chunk
|
|
ei = min(ei, recv_len)
|
|
|
|
chunk_len = ei - si
|
|
|
|
chunk = self._usb.read(chunk_len)
|
|
|
|
data += chunk
|
|
|
|
if len(chunk) < chunk_len:
|
|
break
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
usb = USB_FTX232H_FT60X_sync245mode(device_to_open_list =
|
|
(('FTX232H', 'USB <-> Serial Converter' ), # firstly try to open FTX232H (FT232H or FT2232H) device named 'USB <-> Serial Converter'. Note that 'USB <-> Serial Converter' is the default name of FT232H or FT2232H chip unless the user has modified it. If the chip's name has been modified, you can use FT_Prog software to look up it.
|
|
('FT60X' , 'FTDI SuperSpeed-FIFO Bridge')) # secondly try to open FT60X (FT600 or FT601) device named 'FTDI SuperSpeed-FIFO Bridge'. Note that 'FTDI SuperSpeed-FIFO Bridge' is the default name of FT600 or FT601 chip unless the user has modified it.
|
|
)
|
|
|
|
print('device opened: device_type=%s, device_name=%s' % (usb.device_type, usb.device_name) )
|
|
|
|
usb.close()
|
|
|
|
|