CH34x serial driver added.
pull/6/head
Quan Lin 2019-04-29 14:11:17 +10:00
rodzic d8a6ce598f
commit 0fcfb2a84c
5 zmienionych plików z 1192 dodań i 26 usunięć

Wyświetl plik

@ -7,8 +7,8 @@ Drivers in roadmap are listed below:
* FTDI serial driver - done and tested with FT230X.
* CDC ACM serial driver - done and tested with MCP2200.
* CP210x serial driver - done and tested with CP2102.
* CH34x serial driver - todo.
* Prolific serial driver - todo.
* CH34x serial driver - done and tested with CH340.
* PL2303 serial driver - todo.
Please consider [![Paypal Donate](https://github.com/jacklinquan/images/blob/master/paypal_donate_button_200x80.png)](https://www.paypal.me/jacklinquan) to support me.

Wyświetl plik

@ -2,7 +2,7 @@ from setuptools import setup
setup(
name="usbserial4a",
version="0.1.8",
version="0.1.9",
description="Python package for Kivy Android USB serial port.",
long_description="https://github.com/jacklinquan/usbserial4a",
long_description_content_type="text/markdown",

Wyświetl plik

@ -9,4 +9,4 @@ Requires: kivy, pyjnius, pyserial, usb4a
'''
# Project version
__version__ = '0.1.8'
__version__ = '0.1.9'

Wyświetl plik

@ -0,0 +1,759 @@
'''Android USB serial CH34x driver.
Classes:
Ch34xSerial(serial.serialutil.SerialBase)
'''
from struct import pack, unpack
import time
from serial.serialutil import SerialBase, SerialException, to_bytes, \
portNotOpenError, writeTimeoutError, Timeout
from usb4a import usb
class Ch34xSerial(SerialBase):
'''CH34x serial port class.
Ch34xSerial extends serial.serialutil.SerialBase.
It can be used in a similar way to serial.Serial from pyserial.
'''
# Default baudrate
DEFAULT_BAUDRATE = 9600
# Config request types
REQTYPE_DEVICE_TO_HOST = \
usb.UsbConstants.USB_TYPE_VENDOR | usb.UsbConstants.USB_DIR_IN
REQTYPE_HOST_TO_DEVICE = \
usb.UsbConstants.USB_TYPE_VENDOR | usb.UsbConstants.USB_DIR_OUT
# Config request codes
CH34X_REQ_READ_VERSION = 0x5f
CH34X_REQ_WRITE_REG = 0x9a
CH34X_REQ_READ_REG = 0x95
CH34X_REQ_SERIAL_INIT = 0xa1
CH34X_REQ_MODEM_CTRL = 0xa4
CH34X_REG_BREAK = 0x05
CH34X_REG_LCR = 0x18
CH34X_NBREAK_BITS = 0x01
# LCR values
CH34X_LCR_ENABLE_RX = 0x80
CH34X_LCR_ENABLE_TX = 0x40
CH34X_LCR_MARK_SPACE = 0x20
CH34X_LCR_PAR_EVEN = 0x10
CH34X_LCR_ENABLE_PAR = 0x08
CH34X_LCR_STOP_BITS_2 = 0x04
CH34X_LCR_CS8 = 0x03
CH34X_LCR_CS7 = 0x02
CH34X_LCR_CS6 = 0x01
CH34X_LCR_CS5 = 0x00
# Baud rates values
CH34X_300_1312 = 0xd980
CH34X_300_0f2c = 0xeb
CH34X_600_1312 = 0x6481
CH34X_600_0f2c = 0x76
CH34X_1200_1312 = 0xb281
CH34X_1200_0f2c = 0x3b
CH34X_2400_1312 = 0xd981
CH34X_2400_0f2c = 0x1e
CH34X_4800_1312 = 0x6482
CH34X_4800_0f2c = 0x0f
CH34X_9600_1312 = 0xb282
CH34X_9600_0f2c = 0x08
CH34X_19200_1312 = 0xd982
CH34X_19200_0f2c_rest = 0x07
CH34X_38400_1312 = 0x6483
CH34X_57600_1312 = 0x9883
CH34X_115200_1312 = 0xcc83
CH34X_230400_1312 = 0xe683
CH34X_460800_1312 = 0xf383
CH34X_921600_1312 = 0xf387
# Parity values
CH34X_PARITY_NONE = 0x00
CH34X_PARITY_ODD = 0x08
CH34X_PARITY_EVEN = 0x18
CH34X_PARITY_MARK = 0x28
CH34X_PARITY_SPACE = 0x38
# Flow control values
CH34X_FLOW_CONTROL_NONE = 0x0000
CH34X_FLOW_CONTROL_RTS_CTS = 0x0101
CH34X_FLOW_CONTROL_DSR_DTR = 0x0202
CH34X_CONTROL_DTR = 0x20
CH34X_CONTROL_RTS = 0x40
CH34X_CONTROL_CTS = 0x01
CH34X_CONTROL_DSR = 0x02
CH34X_CONTROL_RI = 0x04
CH34X_CONTROL_DCD = 0x08
# Buffer
DEFAULT_READ_BUFFER_SIZE = 16 * 1024
DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024
# Timeout
USB_READ_TIMEOUT_MILLIS = 5000
USB_WRITE_TIMEOUT_MILLIS = 5000
def __init__(self, *args, **kwargs):
self._device = None
self._connection = None
self._interface = None
self._index = 0
self._control_endpoint = None
self._read_endpoint = None
self._write_endpoint = None
self._lineprop = 0
self._read_buffer = bytearray()
super(Ch34xSerial, self).__init__(*args, **kwargs)
def open(self):
'''Open the serial port.
When the serial port is instantiated, it will try to open automatically.
'''
self.close()
device = usb.get_usb_device(self.portstr)
if not device:
raise SerialException("Device not present {}".format(self.portstr))
if not usb.has_usb_permission(device):
usb.request_usb_permission(device)
return
connection = usb.get_usb_manager().openDevice(device)
if not connection:
raise SerialException("Failed to open device!")
self._device = device
self._connection = connection
for i in range(self._device.getInterfaceCount()):
if not self._connection.claimInterface(
self._device.getInterface(i),
True
):
raise SerialException("Could not claim interface {}.".format(i))
self._interface = self._device.getInterface(
self._device.getInterfaceCount() - 1
)
for i in range(self._interface.getEndpointCount()):
ep = self._interface.getEndpoint(i)
if (
(ep.getDirection() == usb.UsbConstants.USB_DIR_IN) \
and (ep.getType() == usb.UsbConstants.USB_ENDPOINT_XFER_INT)
):
self._control_endpoint = ep
elif (
(ep.getDirection() == usb.UsbConstants.USB_DIR_IN) \
and (ep.getType() == usb.UsbConstants.USB_ENDPOINT_XFER_BULK)
):
self._read_endpoint = ep
elif (
(ep.getDirection() == usb.UsbConstants.USB_DIR_OUT) \
and (ep.getType() == usb.UsbConstants.USB_ENDPOINT_XFER_BULK)
):
self._write_endpoint = ep
# Check that all endpoints are good
if None in [self._write_endpoint, self._read_endpoint]:
raise SerialException("Could not establish all endpoints!")
self._init_device()
self.is_open = True
self._reconfigure_port()
def _reconfigure_port(self):
'''Reconfigure serial port parameters.'''
self._setParameters(
self.baudrate,
self.bytesize,
self.parity,
self.stopbits
)
if self._rtscts:
self._set_flowctrl('hw_rtscts')
elif self._dsrdtr:
self._set_flowctrl('hw_dsrdtr')
elif self._xonxoff:
self._set_flowctrl('sw')
else:
self._set_flowctrl('')
def close(self):
'''Close the serial port.'''
if self._connection:
self._connection.close()
self._connection = None
self.is_open = False
# - - - - - - - - - - - - - - - - - - - - - - - -
@property
def in_waiting(self):
'''Return the number of bytes currently in the input buffer.
Returns:
Length (int): number of data bytes in the input buffer.
'''
# Read from serial port hardware and put the data into read buffer.
self._read_buffer.extend(self._read())
return len(self._read_buffer)
@property
def out_waiting(self):
'''Return the number of bytes currently in the output buffer.
Always return 0.
'''
return 0
def read(self, size=1):
'''Read data from the serial port.
Parameters:
size (int): the number of data bytes to read.
Returns:
read (bytes): data bytes read from the serial port.
'''
read = bytearray()
timeout = Timeout(self.timeout)
# If there is enough data in the buffer, do not bother to read.
if len(self._read_buffer) < size:
# Keep reading until there is enough data or timeout.
while self.in_waiting < size:
if timeout.expired():
break
# Get data from read buffer.
read = self._read_buffer[:size]
self._read_buffer = self._read_buffer[size:]
return bytes(read)
def write(self, data):
'''Write data to the serial port.
Parameters:
data (bytearray): data written to the serial port.
Returns:
wrote (int): the number of data bytes written.
'''
if not self.is_open:
return None
offset = 0
timeout = int(
self._write_timeout * 1000 if self._write_timeout \
else self.USB_WRITE_TIMEOUT_MILLIS
)
wrote = 0
while offset < len(data):
data_length = min(
len(data) - offset,
self.DEFAULT_WRITE_BUFFER_SIZE
)
buf = data[offset:offset + data_length]
i = self._connection.bulkTransfer(
self._write_endpoint,
buf,
data_length,
timeout
)
if i <= 0:
raise SerialException("Failed to write {}: {}".format(buf, i))
offset += data_length
wrote += i
return wrote
def flush(self):
'''Simply wait some time to allow all data to be written.'''
pass
def reset_input_buffer(self):
'''Clear input buffer, discarding all that is in the buffer.'''
if not self.is_open:
raise portNotOpenError
self._purgeHwBuffers(True, False)
def reset_output_buffer(self):
'''\
Clear output buffer, aborting the current output and discarding all
that is in the buffer.
'''
if not self.is_open:
raise portNotOpenError
self._purgeHwBuffers(False, True)
def send_break(self, duration=0.25):
'''Send break condition.
Parameters:
duration (float): break time in seconds.
'''
if not self.is_open:
raise portNotOpenError
self._set_break(True)
time.sleep(duration)
self._set_break(False)
def _update_break_state(self):
'''Send break condition.'''
self._set_break(self._break_state)
def _update_rts_state(self):
'''Set terminal status line: Request To Send.'''
self._set_rts(self._rts_state)
def _update_dtr_state(self):
'''Set terminal status line: Data Terminal Ready.'''
self._set_dtr(self._dtr_state)
@property
def cts(self):
'''Read terminal status line: Clear To Send.'''
status = self._poll_modem_status()
return bool(status & self.CH34X_CONTROL_CTS)
@property
def dsr(self):
'''Read terminal status line: Data Set Ready.'''
status = self._poll_modem_status()
return bool(status & self.CH34X_CONTROL_DSR)
@property
def ri(self):
'''Read terminal status line: Ring Indicator.'''
status = self._poll_modem_status()
return bool(status & self.CH34X_CONTROL_RI)
@property
def cd(self):
'''Read terminal status line: Carrier Detect.'''
status = self._poll_modem_status()
return bool(status & self.CH34X_CONTROL_DCD)
# - - - - - - - - - - - - - - - - - - - - - - - -
def _ctrl_transfer_out(self, request, value, index, buf=None):
'''USB control transfer out.
This function does the USB configuration job.
'''
result = self._connection.controlTransfer(
self.REQTYPE_HOST_TO_DEVICE,
request,
value,
index,
buf,
(0 if buf is None else len(buf)),
self.USB_WRITE_TIMEOUT_MILLIS
)
return result
def _ctrl_transfer_in(self, request, value, index, buf=None):
'''USB control transfer in.
Request for a control message from the device.
'''
result = self._connection.controlTransfer(
self.REQTYPE_DEVICE_TO_HOST,
request,
value,
index,
buf,
(0 if buf is None else len(buf)),
self.USB_READ_TIMEOUT_MILLIS
)
return result
def _check_state(self, msg, request, value, expected):
buf = bytearray(len(expected))
ret = self._ctrl_transfer_in(request, value, 0, buf)
if ret != len(expected):
raise SerialException('Expected {} bytes, got {}, [{}]'.format(
len(expected),
ret,
msg
))
def _init_device(self):
if self._ctrl_transfer_out(0xa1, 0xc29c, 0xb2b9) < 0:
raise SerialException('Init failed! #1')
if self._ctrl_transfer_out(0xa4, 0xdf, 0) < 0:
raise SerialException('Init failed! #2')
if self._ctrl_transfer_out(0xa4, 0x9f, 0) < 0:
raise SerialException('Init failed! #3')
self._check_state(
'Init #4',
self.CH34X_REQ_READ_REG,
0x0706,
[0x9f, 0xee]
)
if self._ctrl_transfer_out(0x9a, 0x2727, 0x0000) < 0:
raise SerialException('Init failed! #5')
if self._ctrl_transfer_out(0x9a, 0x1312, 0xb282) < 0:
raise SerialException('Init failed! #6')
if self._ctrl_transfer_out(0x9a, 0x0f2c, 0x0008) < 0:
raise SerialException('Init failed! #7')
if self._ctrl_transfer_out(0x9a, 0x2518, 0x00c3) < 0:
raise SerialException('Init failed! #8')
self._check_state(
'Init #9',
self.CH34X_REQ_READ_REG,
0x0706,
[0x9f, 0xee]
)
if self._ctrl_transfer_out(0x9a, 0x2727, 0x0000) < 0:
raise SerialException('Init failed! #10')
def _set_break(self, break_):
'''Start or stop a break exception event on the serial line.
Parameters:
break_ (bool): either start or stop break event.
'''
ch34x_break_reg = (self.CH34X_REG_LCR << 8) | self.CH34X_REG_BREAK
break_reg = bytearray(2)
if self._ctrl_transfer_in(
self.CH34X_REQ_READ_REG,
ch34x_break_reg,
0,
break_reg
) < 0:
raise SerialException('Unable to read break state!')
if break_:
break_reg[0] &= (~self.CH34X_NBREAK_BITS)
break_reg[1] &= (~self.CH34X_LCR_ENABLE_TX)
else:
break_reg[0] |= self.CH34X_NBREAK_BITS
break_reg[1] |= self.CH34X_LCR_ENABLE_TX
#Unpack break_reg into int
reg_contents = break_reg[1] * 256 + break_reg[0]
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
ch34x_break_reg,
reg_contents
) < 0:
raise SerialException('Unable to set break state!')
def _set_dtr(self, state):
'''Set dtr line.
Parameters:
state (bool): new DTR logical level.
'''
self._set_dtr_rts(state, self._rts_state)
def _set_rts(self, state):
'''Set rts line.
Parameters:
state (bool): new RTS logical level.
'''
self._set_dtr_rts(self._dtr_state, state)
def _set_dtr_rts(self, dtr, rts):
'''Set dtr and rts lines at once.
Parameters:
dtr (bool): new DTR logical level.
rts (bool): new RTS logical level.
'''
value = 0
if dtr:
value |= self.CH34X_CONTROL_DTR
if rts:
value |= self.CH34X_CONTROL_RTS
if self._ctrl_transfer_out(
self.CH34X_REQ_MODEM_CTRL,
~value,
0
) < 0:
raise SerialException('Unable to set DTR/RTS lines!')
def _purgeHwBuffers(self, purgeReadBuffers, purgeWriteBuffers):
'''Set serial port parameters.
Parameters:
purgeReadBuffers (bool): need to purge read buffer or not.
purgeWriteBuffers (bool): need to purge write buffer or not.
Returns:
result (bool): successful or not.
'''
return True
def _read(self):
'''Hardware dependent read function.
Returns:
read (bytes): data bytes read from the serial port.
'''
if not self.is_open:
raise portNotOpenError
if not self._read_endpoint:
raise SerialException("Read endpoint does not exist!")
# Get raw data from hardware.
buf = bytearray(self.DEFAULT_READ_BUFFER_SIZE)
totalBytesRead = self._connection.bulkTransfer(
self._read_endpoint,
buf,
self.DEFAULT_READ_BUFFER_SIZE,
self.USB_READ_TIMEOUT_MILLIS
)
if totalBytesRead < 0:
# Read timeout. Set totalBytesRead to 0.
totalBytesRead = 0
read = buf[:totalBytesRead]
return bytes(read)
def _set_baudrate(self, baudrate):
'''Change the current UART baudrate.
Parameters:
baudrate (int): the new baudrate for the UART.
Raises:
SerialException: if not able to set baudrate.
'''
if baudrate <= 300:
index1312 = self.CH34X_300_1312
index0f2c = self.CH34X_300_0f2c
elif 300 < baudrate <= 600:
index1312 = self.CH34X_600_1312
index0f2c = self.CH34X_600_0f2c
elif 600 < baudrate <= 1200:
index1312 = self.CH34X_1200_1312
index0f2c = self.CH34X_1200_0f2c
elif 1200 < baudrate <= 2400:
index1312 = self.CH34X_2400_1312
index0f2c = self.CH34X_2400_0f2c
elif 2400 < baudrate <= 4800:
index1312 = self.CH34X_4800_1312
index0f2c = self.CH34X_4800_0f2c
elif 4800 < baudrate <= 9600:
index1312 = self.CH34X_9600_1312
index0f2c = self.CH34X_9600_0f2c
elif 9600 < baudrate <= 19200:
index1312 = self.CH34X_19200_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 19200 < baudrate <= 38400:
index1312 = self.CH34X_38400_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 38400 < baudrate <= 57600:
index1312 = self.CH34X_57600_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 57600 < baudrate <= 115200:
index1312 = self.CH34X_115200_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 115200 < baudrate <= 230400:
index1312 = self.CH34X_230400_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 230400 < baudrate <= 460800:
index1312 = self.CH34X_460800_1312
index0f2c = self.CH34X_19200_0f2c_rest
elif 460800 < baudrate <= 921600:
index1312 = self.CH34X_921600_1312
index0f2c = self.CH34X_19200_0f2c_rest
else:
raise SerialException("Baudrate out of range!")
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x1312,
index1312
) < 0:
raise SerialException('Fail to set baudrate index1312!')
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x0f2c,
index0f2c
) < 0:
raise SerialException('Fail to set baudrate index0f2c!')
self._check_state(
'Set baudrate',
self.CH34X_REQ_READ_REG,
0x0706,
[0x9f, 0xee]
)
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x2727,
0
) < 0:
raise SerialException('Fail to set baudrate!')
def _set_line_property(self, bits, stopbits, parity):
'''Set serial port line property.
Parameters:
bits (int): number of bits in data(5, 6, 7 or 8).
stopbits (float): number of stop bits(1, 1.5, 2).
parity (str): 'N', 'E', 'O', 'M' or 'S'.
'''
lcr = self.CH34X_LCR_ENABLE_RX | self.CH34X_LCR_ENABLE_TX
if bits == 5:
lcr |= self.CH34X_LCR_CS5
elif bits == 6:
lcr |= self.CH34X_LCR_CS6
elif bits == 7:
lcr |= self.CH34X_LCR_CS7
elif bits == 8:
lcr |= self.CH34X_LCR_CS8
else:
raise ValueError('Unknown bits value: {}'.format(bits))
if parity == 'N':
pass
elif parity == 'O':
lcr |= (self.CH34X_LCR_ENABLE_PAR)
elif parity == 'E':
lcr |= (self.CH34X_LCR_ENABLE_PAR | self.CH34X_LCR_PAR_EVEN)
elif parity == 'M':
lcr |= (self.CH34X_LCR_ENABLE_PAR | self.CH34X_LCR_MARK_SPACE)
elif parity == 'S':
lcr |= (
self.CH34X_LCR_ENABLE_PAR \
| self.CH34X_LCR_MARK_SPACE \
| self.CH34X_LCR_PAR_EVEN
)
else:
raise ValueError('Unknown parity value: {}'.format(parity))
if stopbits == 1:
pass
elif stopbits == 1.5:
pass
elif stopbits == 2:
lcr |= self.CH34X_LCR_STOP_BITS_2
else:
raise ValueError('Unknown stopbits value: {}'.format(stopbits))
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x2518,
lcr
) < 0:
raise SerialException('Setting line property failed!')
self._check_state(
'Set parity',
self.CH34X_REQ_READ_REG,
0x0706,
[0x9f, 0xee]
)
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x2727,
0
) < 0:
raise SerialException('Fail to set line property!')
self._lineprop = lcr
def _setParameters(self, baudrate, databits, parity, stopbits):
'''Set serial port parameters.
Parameters:
baudrate (int): the new baudrate for the UART(eg 9600).
databits (int): number of bits in data(5, 6, 7 or 8).
parity (str): 'N', 'E', 'O', 'M' or 'S'.
stopbits (float): number of stop bits(1, 1.5, 2).
'''
self._set_baudrate(baudrate)
self._set_line_property(databits, stopbits, parity)
def _poll_modem_status(self):
'''Poll modem status information.
This function allows the retrieve the one status byte of the
device, useful in UART mode.
Returns:
status (int): modem status, as a proprietary bitfield
'''
buf = bytearray(2)
result = self._ctrl_transfer_in(
self.CH34X_REQ_READ_REG,
0x0706,
0,
buf
)
if result != 2:
raise SerialException('Unable to get modem status!')
buf = buf[:2]
status, = unpack('<H', bytes(buf))
return status
def _set_flowctrl(self, flowctrl):
'''Select flowcontrol in UART mode.
Either hardware flow control through RTS/CTS or DSR/DTR,
software flow control or no flow control.
Parameters:
flowctrl (str): 'hw_rtscts', 'hw_dsrdtr', 'sw' or ''
'''
if flowctrl == 'hw_rtscts':
ch34x_flowctrl = self.CH34X_FLOW_CONTROL_RTS_CTS
self.rts = True
elif flowctrl == 'hw_dsrdtr':
ch34x_flowctrl = self.CH34X_FLOW_CONTROL_DSR_DTR
self.dtr = True
#elif flowctrl == 'sw':
else:
ch34x_flowctrl = self.CH34X_FLOW_CONTROL_NONE
self._check_state(
'Set flow control',
self.CH34X_REQ_READ_REG,
0x0706,
[0x9f, 0xee]
)
if self._ctrl_transfer_out(
self.CH34X_REQ_WRITE_REG,
0x2727,
ch34x_flowctrl
) < 0:
raise SerialException('Setting flow control failed!')

Wyświetl plik

@ -8,29 +8,418 @@ from usb4a import usb
from .ftdiserial4a import FtdiSerial
from .cdcacmserial4a import CdcAcmSerial
from .cp210xserial4a import Cp210xSerial
from .ch34xserial4a import Ch34xSerial
#from .pl2303serial4a import Pl2303Serial
FTDI_VENDOR_ID = 0x0403
SILABS_VENDOR_ID = 0x10C4
VENDOR_IDS = {
'ftdi': FTDI_VENDOR_ID,
'silabs': SILABS_VENDOR_ID
}
PRODUCT_IDS = {
FTDI_VENDOR_ID: {
'ft232': 0x6001,
'ft232r': 0x6001,
'ft232h': 0x6014,
'ft2232': 0x6010,
'ft2232d': 0x6010,
'ft2232h': 0x6010,
'ft4232': 0x6011,
'ft4232h': 0x6011,
'ft230x': 0x6015
},
SILABS_VENDOR_ID: {
'cp2102': 0xEA60
}
}
QINHENG_VENDOR_ID = 0x1A86
PROLIFIC_VENDOR_ID = 0x067B
FTDI_VID_PID_GROUP = [
(0x03eb, 0x2109),
(0x0456, 0xf000),
(0x0456, 0xf001),
(0x04d8, 0x000a),
(0x0584, 0xb020),
(0x0647, 0x0100),
(0x06CE, 0x8311),
(0x06D3, 0x0284),
(0x0856, 0xac01),
(0x0856, 0xac02),
(0x0856, 0xac03),
(0x0856, 0xac11),
(0x0856, 0xac12),
(0x0856, 0xac16),
(0x0856, 0xac17),
(0x0856, 0xac18),
(0x0856, 0xac19),
(0x0856, 0xac25),
(0x0856, 0xac26),
(0x0856, 0xac27),
(0x0856, 0xac33),
(0x0856, 0xac34),
(0x0856, 0xac49),
(0x0856, 0xac50),
(0x0856, 0xba02),
(0x093c, 0x0601),
(0x093c, 0x0701),
(0x0acd, 0x0300),
(0x0b39, 0x0103),
(0x0b39, 0x0421),
(0x0c26, 0x0004),
(0x0c26, 0x0018),
(0x0c26, 0x0009),
(0x0c26, 0x000a),
(0x0c26, 0x000b),
(0x0c26, 0x000c),
(0x0c26, 0x000d),
(0x0c26, 0x0010),
(0x0c26, 0x0011),
(0x0c26, 0x0012),
(0x0c26, 0x0013),
(0x0c33, 0x0010),
(0x0c52, 0x2101),
(0x0c52, 0x2101),
(0x0c52, 0x2102),
(0x0c52, 0x2103),
(0x0c52, 0x2104),
(0x0c52, 0x9020),
(0x0c52, 0x2211),
(0x0c52, 0x2221),
(0x0c52, 0x2212),
(0x0c52, 0x2222),
(0x0c52, 0x2213),
(0x0c52, 0x2223),
(0x0c52, 0x2411),
(0x0c52, 0x2421),
(0x0c52, 0x2431),
(0x0c52, 0x2441),
(0x0c52, 0x2412),
(0x0c52, 0x2422),
(0x0c52, 0x2432),
(0x0c52, 0x2442),
(0x0c52, 0x2413),
(0x0c52, 0x2423),
(0x0c52, 0x2433),
(0x0c52, 0x2443),
(0x0c52, 0x2811),
(0x0c52, 0x2821),
(0x0c52, 0x2831),
(0x0c52, 0x2841),
(0x0c52, 0x2851),
(0x0c52, 0x2861),
(0x0c52, 0x2871),
(0x0c52, 0x2881),
(0x0c52, 0x2812),
(0x0c52, 0x2822),
(0x0c52, 0x2832),
(0x0c52, 0x2842),
(0x0c52, 0x2852),
(0x0c52, 0x2862),
(0x0c52, 0x2872),
(0x0c52, 0x2882),
(0x0c52, 0x2813),
(0x0c52, 0x2823),
(0x0c52, 0x2833),
(0x0c52, 0x2843),
(0x0c52, 0x2853),
(0x0c52, 0x2863),
(0x0c52, 0x2873),
(0x0c52, 0x2883),
(0x0c52, 0xa02a),
(0x0c52, 0xa02b),
(0x0c52, 0xa02c),
(0x0c52, 0xa02d),
(0x0c6c, 0x04b2),
(0x0c7d, 0x0005),
(0x0d3a, 0x0300),
(0x0d46, 0x2020),
(0x0d46, 0x2021),
(0x0dcd, 0x0001),
(0x0f94, 0x0001),
(0x0f94, 0x0005),
(0x0fd8, 0x0001),
(0x103e, 0x03e8),
(0x104d, 0x3000),
(0x104d, 0x3002),
(0x104d, 0x3006),
(0x1209, 0x1002),
(0x1209, 0x1006),
(0x128d, 0x0001),
(0x1342, 0x0202),
(0x1457, 0x5118),
(0x15ba, 0x0003),
(0x15ba, 0x002b),
(0x1781, 0x0c30),
(0x2100, 0x9001),
(0x2100, 0x9e50),
(0x2100, 0x9e51),
(0x2100, 0x9e52),
(0x2100, 0x9e53),
(0x2100, 0x9e54),
(0x2100, 0x9e55),
(0x2100, 0x9e56),
(0x2100, 0x9e57),
(0x2100, 0x9e58),
(0x2100, 0x9e59),
(0x2100, 0x9e5a),
(0x2100, 0x9e5b),
(0x2100, 0x9e5c),
(0x2100, 0x9e5d),
(0x2100, 0x9e5e),
(0x2100, 0x9e5f),
(0x2100, 0x9e60),
(0x2100, 0x9e61),
(0x2100, 0x9e62),
(0x2100, 0x9e63),
(0x2100, 0x9e64),
(0x2100, 0x9e65),
(0x2100, 0x9e65),
(0x2100, 0x9e66),
(0x2100, 0x9e67),
(0x2100, 0x9e68),
(0x2100, 0x9e69),
(0x2100, 0x9e6a),
(0x1a72, 0x1000),
(0x1a72, 0x1001),
(0x1a72, 0x1002),
(0x1a72, 0x1005),
(0x1a72, 0x1007),
(0x1a72, 0x1008),
(0x1a72, 0x1009),
(0x1a72, 0x100d),
(0x1a72, 0x100e),
(0x1a72, 0x100f),
(0x1a72, 0x1011),
(0x1a72, 0x1012),
(0x1a72, 0x1013),
(0x1a72, 0x1014),
(0x1a72, 0x1015),
(0x1a72, 0x1016),
(0x165c, 0x0002),
(0x1a79, 0x6001),
(0x1b3d, 0x0100),
(0x1b3d, 0x0101),
(0x1b3d, 0x0102),
(0x1b3d, 0x0103),
(0x1b3d, 0x0104),
(0x1b3d, 0x0105),
(0x1b3d, 0x0106),
(0x1b3d, 0x0107),
(0x1b3d, 0x0108),
(0x1b3d, 0x0109),
(0x1b3d, 0x010a),
(0x1b3d, 0x010b),
(0x1b3d, 0x010c),
(0x1b3d, 0x010d),
(0x1b3d, 0x010e),
(0x1b3d, 0x010f),
(0x1b3d, 0x0110),
(0x1b3d, 0x0111),
(0x1b3d, 0x0112),
(0x1b3d, 0x0113),
(0x1b3d, 0x0114),
(0x1b3d, 0x0115),
(0x1b3d, 0x0116),
(0x1b3d, 0x0117),
(0x1b3d, 0x0118),
(0x1b3d, 0x0119),
(0x1b3d, 0x011a),
(0x1b3d, 0x011b),
(0x1b3d, 0x011c),
(0x1b3d, 0x011d),
(0x1b3d, 0x011e),
(0x1b3d, 0x011f),
(0x1b3d, 0x0120),
(0x1b3d, 0x0121),
(0x1b3d, 0x0122),
(0x1b3d, 0x0123),
(0x1b3d, 0x0124),
(0x1b3d, 0x0125),
(0x1b3d, 0x0126),
(0x1b3d, 0x0127),
(0x1b3d, 0x0128),
(0x1b3d, 0x0129),
(0x1b3d, 0x012a),
(0x1b3d, 0x012b),
(0x1b3d, 0x012c),
(0x1b3d, 0x012e),
(0x1b3d, 0x012f),
(0x1b3d, 0x0130),
(0x1b91, 0x0064),
(0x1bc9, 0x6001),
(0x1c0c, 0x0102),
(0x1cf1, 0x0001),
(0x1cf1, 0x0041),
(0x0483, 0x3746),
(0x0483, 0x3747),
(0x5050, 0x0100),
(0x5050, 0x0101),
(0x5050, 0x0102),
(0x5050, 0x0103),
(0x5050, 0x0104),
(0x5050, 0x0105),
(0x5050, 0x0106),
(0x5050, 0x0107),
(0x5050, 0x0300),
(0x5050, 0x0301),
(0x5050, 0x0400),
(0x5050, 0x0500),
(0x5050, 0x0700),
(0x5050, 0x0800),
(0x5050, 0x0900),
(0x5050, 0x0a00),
(0x5050, 0x0b00),
(0x5050, 0x0c00),
(0x5050, 0x0d00),
(0x5050, 0x0e00),
(0x5050, 0x0f00),
(0x5050, 0x1000),
(0x5050, 0x8000),
(0x5050, 0x8001),
(0x5050, 0x8002),
(0x5050, 0x8003),
(0x5050, 0x8004),
(0x5050, 0x8005),
(0x9e88, 0x9e8f),
(0xdeee, 0x0300),
(0xdeee, 0x02ff),
(0xdeee, 0x0302),
(0xdeee, 0x0303),
(0x05d1, 0x1001),
(0x05d1, 0x1002),
(0x05d1, 0x1003),
(0x05d1, 0x1004),
(0x05d1, 0x1011),
(0x05d1, 0x1013),
(0x05d1, 0x2001),
(0x05d1, 0x2002),
(0x05d1, 0x2003),
(0x05d1, 0x2011),
(0x05d1, 0x2012),
(0x05d1, 0x2021),
(0x05d1, 0x2022),
(0x05d1, 0x2023),
(0x05d1, 0x2024),
(0x05d1, 0x3011),
(0x05d1, 0x3012),
(0x05d1, 0x5001),
(0x05d1, 0x6001),
(0x05d1, 0x7001),
(0x05d1, 0x8001),
(0x05d1, 0x8002),
(0x05d1, 0x8003),
(0x05d1, 0x8004),
(0x05d1, 0x9001),
(0x05d1, 0x9002),
(0x05d1, 0x9003),
(0x05d1, 0x9004),
(0x05d1, 0x9005),
(0x05d1, 0x9006),
(0x05d1, 0x9007),
(0x05d1, 0x9008)
]
SILABS_VID_PID_GROUP = [
(0x045B, 0x0053),
(0x0471, 0x066A),
(0x0489, 0xE000),
(0x0489, 0xE003),
(0x0745, 0x1000),
(0x0846, 0x1100),
(0x08e6, 0x5501),
(0x08FD, 0x000A),
(0x0BED, 0x1100),
(0x0BED, 0x1101),
(0x0FCF, 0x1003),
(0x0FCF, 0x1004),
(0x0FCF, 0x1006),
(0x0FDE, 0xCA05),
(0x10A6, 0xAA26),
(0x10AB, 0x10C5),
(0x10B5, 0xAC70),
(0x2405, 0x0003),
(0x10C5, 0xEA61),
(0x10CE, 0xEA6A),
(0x13AD, 0x9999),
(0x1555, 0x0004),
(0x166A, 0x0201),
(0x166A, 0x0301),
(0x166A, 0x0303),
(0x166A, 0x0304),
(0x166A, 0x0305),
(0x166A, 0x0401),
(0x166A, 0x0101),
(0x16D6, 0x0001),
(0x16DC, 0x0010),
(0x16DC, 0x0011),
(0x16DC, 0x0012),
(0x16DC, 0x0015),
(0x17A8, 0x0001),
(0x17A8, 0x0005),
(0x17F4, 0xAAAA),
(0x1843, 0x0200),
(0x18EF, 0xE00F),
(0x1ADB, 0x0001),
(0x1BE3, 0x07A6),
(0x1E29, 0x0102),
(0x1E29, 0x0501),
(0x1FB9, 0x0100),
(0x1FB9, 0x0200),
(0x1FB9, 0x0201),
(0x1FB9, 0x0202),
(0x1FB9, 0x0203),
(0x1FB9, 0x0300),
(0x1FB9, 0x0301),
(0x1FB9, 0x0302),
(0x1FB9, 0x0303),
(0x1FB9, 0x0400),
(0x1FB9, 0x0401),
(0x1FB9, 0x0402),
(0x1FB9, 0x0403),
(0x1FB9, 0x0404),
(0x1FB9, 0x0600),
(0x1FB9, 0x0601),
(0x1FB9, 0x0602),
(0x1FB9, 0x0700),
(0x1FB9, 0x0701),
(0x3195, 0xF190),
(0x3195, 0xF280),
(0x3195, 0xF281),
(0x413C, 0x9500),
(0x1908, 0x2311)
]
QINHENG_VID_PID_GROUP = [
(0x4348, 0x5523)
]
PROLIFIC_VID_PID_GROUP = [
(0x04a5, 0x4027),
(0x0557, 0x2008),
(0x0547, 0x2008),
(0x04bb, 0x0a03),
(0x04bb, 0x0a0e),
(0x056e, 0x5003),
(0x056e, 0x5004),
(0x0eba, 0x1080),
(0x0eba, 0x2080),
(0x0df7, 0x0620),
(0x0584, 0xb000),
(0x2478, 0x2008),
(0x1453, 0x4026),
(0x0731, 0x0528),
(0x6189, 0x2068),
(0x11f7, 0x02df),
(0x04e8, 0x8001),
(0x11f5, 0x0001),
(0x11f5, 0x0003),
(0x11f5, 0x0004),
(0x11f5, 0x0005),
(0x0745, 0x0001),
(0x078b, 0x1234),
(0x10b5, 0xac70),
(0x079b, 0x0027),
(0x0413, 0x2101),
(0x0e55, 0x110b),
(0x0731, 0x2003),
(0x050d, 0x0257),
(0x058f, 0x9720),
(0x11f6, 0x2001),
(0x07aa, 0x002a),
(0x05ad, 0x0fba),
(0x5372, 0x2303),
(0x03f0, 0x0b39),
(0x03f0, 0x3139),
(0x03f0, 0x3239),
(0x03f0, 0x3524),
(0x04b8, 0x0521),
(0x04b8, 0x0522),
(0x054c, 0x0437),
(0x11ad, 0x0001),
(0x0b63, 0x6530),
(0x0b8c, 0x2303),
(0x110a, 0x1150),
(0x0557, 0x2008)
]
def get_serial_port(device_name, *args, **kwargs):
'''Get a USB serial port from the system.
@ -47,10 +436,28 @@ def get_serial_port(device_name, *args, **kwargs):
device = usb.get_usb_device(device_name)
if device:
device_vid = device.getVendorId()
if device_vid == VENDOR_IDS['ftdi']:
device_pid = device.getProductId()
if (
device_vid == FTDI_VENDOR_ID \
or (device_vid, device_pid) in FTDI_VID_PID_GROUP
):
return FtdiSerial(device_name, *args, **kwargs)
elif device_vid == VENDOR_IDS['silabs']:
elif (
device_vid == SILABS_VENDOR_ID \
or (device_vid, device_pid) in SILABS_VID_PID_GROUP
):
return Cp210xSerial(device_name, *args, **kwargs)
elif (
device_vid == QINHENG_VENDOR_ID \
or (device_vid, device_pid) in QINHENG_VID_PID_GROUP
):
return Ch34xSerial(device_name, *args, **kwargs)
elif (
device_vid == PROLIFIC_VENDOR_ID \
or (device_vid, device_pid) in PROLIFIC_VID_PID_GROUP
):
#return Pl2303Serial(device_name, *args, **kwargs)
raise Exception('PL2303 serial driver is not implemented yet!')
else:
return CdcAcmSerial(device_name, *args, **kwargs)
else: