Add full CP210x API coverage: 29 tools, all part families

Complete ctypes bindings for all 45 libcp210xmanufacturing functions
including structs (BAUD_CONFIG, PORT_CONFIG, DUAL_PORT_CONFIG,
QUAD_PORT_CONFIG, FIRMWARE_T), part-number gating, bitmask helpers,
and three-tier safety model (none/normal/strict elicitation).

New tools: set_vid, set_pid, get/set_interface_string,
get/set_flush_buffer_config, get/set_device_mode,
get_firmware_version, set_device_version, get/set_baud_rate_config,
set_baud_rate_alias, get/set_port_config, get/set_raw_config,
create_hex_file, update_firmware.
This commit is contained in:
Ryan Malloy 2026-01-31 09:46:43 -07:00
parent 80220f5728
commit c0bedde54b
3 changed files with 1301 additions and 331 deletions

View File

@ -1,5 +1,5 @@
"""mcp210x-uart - MCP server for Silicon Labs CP210x USB-UART bridge customization.""" """mcp210x-uart - MCP server for Silicon Labs CP210x USB-UART bridge customization."""
from .server import mcp, main from .server import main, mcp
__all__ = ["mcp", "main"] __all__ = ["mcp", "main"]

View File

@ -1,9 +1,8 @@
"""Low-level ctypes bindings for libcp210xmanufacturing.""" """Low-level ctypes bindings for libcp210xmanufacturing."""
import ctypes import ctypes
from ctypes import c_int, c_uint, c_ushort, c_ubyte, c_char_p, c_void_p, POINTER, byref from ctypes import POINTER, Structure, byref, c_char_p, c_int, c_ubyte, c_uint, c_ushort, c_void_p
from pathlib import Path from pathlib import Path
from typing import Optional
# Type aliases matching the C library # Type aliases matching the C library
CP210x_STATUS = c_int CP210x_STATUS = c_int
@ -39,17 +38,238 @@ PART_NUMBERS = {
0x22: "CP2102N-QFN20", 0x22: "CP2102N-QFN20",
} }
# Part number groups for feature gating
PARTS_CP2102N = {0x20, 0x21, 0x22}
PARTS_WITH_FLUSH_CONFIG = {0x04, 0x05, 0x08} # CP2104, CP2105, CP2108
PARTS_WITH_DEVICE_MODE = {0x05} # CP2105 only
PARTS_WITH_INTERFACE_STRING = {0x05, 0x08} # CP2105, CP2108
PARTS_WITH_PORT_CONFIG = {0x03, 0x04} # CP2103, CP2104
PARTS_WITH_DUAL_PORT_CONFIG = {0x05} # CP2105
PARTS_WITH_QUAD_PORT_CONFIG = {0x08} # CP2108
# Buffer sizes # Buffer sizes
MAX_DEVICE_STRLEN = 256 MAX_DEVICE_STRLEN = 256
MAX_MANUFACTURER_STRLEN = 45 MAX_MANUFACTURER_STRLEN = 45
MAX_PRODUCT_STRLEN = 126 MAX_PRODUCT_STRLEN = 126
MAX_SERIAL_STRLEN = 63 MAX_SERIAL_STRLEN = 63
CP2105_MAX_INTERFACE_STRLEN = 32
CP2108_MAX_INTERFACE_STRLEN = 126
# GetProductString flags # GetProductString flags
RETURN_SERIAL_NUMBER = 0x00 RETURN_SERIAL_NUMBER = 0x00
RETURN_DESCRIPTION = 0x01 RETURN_DESCRIPTION = 0x01
RETURN_FULL_PATH = 0x02 RETURN_FULL_PATH = 0x02
# Flush buffer config flags (CP2104)
FC_OPEN_TX = 0x01
FC_OPEN_RX = 0x02
FC_CLOSE_TX = 0x04
FC_CLOSE_RX = 0x08
# CP2105 standard port
FC_OPEN_TX_SCI = FC_OPEN_TX
FC_OPEN_RX_SCI = FC_OPEN_RX
FC_CLOSE_TX_SCI = FC_CLOSE_TX
FC_CLOSE_RX_SCI = FC_CLOSE_RX
# CP2105 enhanced port
FC_OPEN_TX_ECI = 0x10
FC_OPEN_RX_ECI = 0x20
FC_CLOSE_TX_ECI = 0x40
FC_CLOSE_RX_ECI = 0x80
# CP2108 per-interface
FC_OPEN_TX_IFC0 = 0x0001
FC_OPEN_RX_IFC0 = 0x0002
FC_CLOSE_TX_IFC0 = 0x0004
FC_CLOSE_RX_IFC0 = 0x0008
FC_OPEN_TX_IFC1 = 0x0010
FC_OPEN_RX_IFC1 = 0x0020
FC_CLOSE_TX_IFC1 = 0x0040
FC_CLOSE_RX_IFC1 = 0x0080
FC_OPEN_TX_IFC2 = 0x0100
FC_OPEN_RX_IFC2 = 0x0200
FC_CLOSE_TX_IFC2 = 0x0400
FC_CLOSE_RX_IFC2 = 0x0800
FC_OPEN_TX_IFC3 = 0x1000
FC_OPEN_RX_IFC3 = 0x2000
FC_CLOSE_TX_IFC3 = 0x4000
FC_CLOSE_RX_IFC3 = 0x8000
# Baud rate config
NUM_BAUD_CONFIGS = 32
BAUD_CONFIG_SIZE = 10
# Port config pin flags (CP2103/CP2104)
PORT_RI_ON = 0x0001
PORT_DCD_ON = 0x0002
PORT_DTR_ON = 0x0004
PORT_DSR_ON = 0x0008
PORT_TXD_ON = 0x0010
PORT_RXD_ON = 0x0020
PORT_RTS_ON = 0x0040
PORT_CTS_ON = 0x0080
PORT_GPIO_0_ON = 0x0100
PORT_GPIO_1_ON = 0x0200
PORT_GPIO_2_ON = 0x0400
PORT_GPIO_3_ON = 0x0800
PORT_SUSPEND_ON = 0x4000
PORT_SUSPEND_BAR_ON = 0x8000
# Enhanced function flags (CP2103/CP2104)
EF_GPIO_0_TXLED = 0x01
EF_GPIO_1_RXLED = 0x02
EF_GPIO_2_RS485 = 0x04
EF_RS485_INVERT = 0x08
EF_WEAKPULLUP = 0x10
EF_RESERVED_1 = 0x20
EF_SERIAL_DYNAMIC_SUSPEND = 0x40
EF_GPIO_DYNAMIC_SUSPEND = 0x80
# Flush buffer flag names for human-readable output
FLUSH_FLAGS_CP2104 = {
FC_OPEN_TX: "open_tx",
FC_OPEN_RX: "open_rx",
FC_CLOSE_TX: "close_tx",
FC_CLOSE_RX: "close_rx",
}
FLUSH_FLAGS_CP2105 = {
FC_OPEN_TX_SCI: "open_tx_sci",
FC_OPEN_RX_SCI: "open_rx_sci",
FC_CLOSE_TX_SCI: "close_tx_sci",
FC_CLOSE_RX_SCI: "close_rx_sci",
FC_OPEN_TX_ECI: "open_tx_eci",
FC_OPEN_RX_ECI: "open_rx_eci",
FC_CLOSE_TX_ECI: "close_tx_eci",
FC_CLOSE_RX_ECI: "close_rx_eci",
}
ENHANCED_FXN_FLAGS = {
EF_GPIO_0_TXLED: "gpio0_txled",
EF_GPIO_1_RXLED: "gpio1_rxled",
EF_GPIO_2_RS485: "gpio2_rs485",
EF_RS485_INVERT: "rs485_invert",
EF_WEAKPULLUP: "weak_pullup",
EF_SERIAL_DYNAMIC_SUSPEND: "serial_dynamic_suspend",
EF_GPIO_DYNAMIC_SUSPEND: "gpio_dynamic_suspend",
}
PORT_PIN_FLAGS = {
PORT_RI_ON: "RI",
PORT_DCD_ON: "DCD",
PORT_DTR_ON: "DTR",
PORT_DSR_ON: "DSR",
PORT_TXD_ON: "TXD",
PORT_RXD_ON: "RXD",
PORT_RTS_ON: "RTS",
PORT_CTS_ON: "CTS",
PORT_GPIO_0_ON: "GPIO0",
PORT_GPIO_1_ON: "GPIO1",
PORT_GPIO_2_ON: "GPIO2",
PORT_GPIO_3_ON: "GPIO3",
PORT_SUSPEND_ON: "SUSPEND",
PORT_SUSPEND_BAR_ON: "SUSPEND_BAR",
}
def decode_bitmask(value: int, flag_map: dict) -> dict[str, bool]:
"""Decode a bitmask into a dict of named flags."""
return {name: bool(value & bit) for bit, name in flag_map.items()}
def encode_bitmask(flags: dict[str, bool], flag_map: dict) -> int:
"""Encode a dict of named flags back into a bitmask."""
name_to_bit = {name: bit for bit, name in flag_map.items()}
value = 0
for name, enabled in flags.items():
if name in name_to_bit and enabled:
value |= name_to_bit[name]
return value
# --- ctypes Structures ---
class BAUD_CONFIG(Structure):
_pack_ = 1
_fields_ = [
("BaudGen", WORD),
("Timer0Reload", WORD),
("Prescaler", BYTE),
("_pad", BYTE),
("BaudRate", DWORD),
]
assert ctypes.sizeof(BAUD_CONFIG) == BAUD_CONFIG_SIZE
BAUD_CONFIG_DATA = BAUD_CONFIG * NUM_BAUD_CONFIGS
class PORT_CONFIG(Structure):
_fields_ = [
("Mode", WORD),
("Reset_Latch", WORD),
("Suspend_Latch", WORD),
("EnhancedFxn", BYTE),
]
class DUAL_PORT_CONFIG(Structure):
_fields_ = [
("Mode", WORD),
("Reset_Latch", WORD),
("Suspend_Latch", WORD),
("EnhancedFxn_ECI", BYTE),
("EnhancedFxn_SCI", BYTE),
("EnhancedFxn_Device", BYTE),
]
class QUAD_PORT_STATE(Structure):
_fields_ = [
("Mode_PB0", WORD),
("Mode_PB1", WORD),
("Mode_PB2", WORD),
("Mode_PB3", WORD),
("Mode_PB4", WORD),
("LowPower_PB0", WORD),
("LowPower_PB1", WORD),
("LowPower_PB2", WORD),
("LowPower_PB3", WORD),
("LowPower_PB4", WORD),
("Latch_PB0", WORD),
("Latch_PB1", WORD),
("Latch_PB2", WORD),
("Latch_PB3", WORD),
("Latch_PB4", WORD),
]
class QUAD_PORT_CONFIG(Structure):
_fields_ = [
("Reset_Latch", QUAD_PORT_STATE),
("Suspend_Latch", QUAD_PORT_STATE),
("IPDelay_IFC0", BYTE),
("IPDelay_IFC1", BYTE),
("IPDelay_IFC2", BYTE),
("IPDelay_IFC3", BYTE),
("EnhancedFxn_IFC0", BYTE),
("EnhancedFxn_IFC1", BYTE),
("EnhancedFxn_IFC2", BYTE),
("EnhancedFxn_IFC3", BYTE),
("EnhancedFxn_Device", BYTE),
("ExtClk0Freq", BYTE),
("ExtClk1Freq", BYTE),
("ExtClk2Freq", BYTE),
("ExtClk3Freq", BYTE),
]
class FIRMWARE_T(Structure):
_fields_ = [
("major", BYTE),
("minor", BYTE),
("build", BYTE),
]
class CP210xError(Exception): class CP210xError(Exception):
"""Exception raised for CP210x library errors.""" """Exception raised for CP210x library errors."""
@ -77,16 +297,10 @@ class CP210xError(Exception):
class CP210xLibrary: class CP210xLibrary:
"""Wrapper for the CP210x manufacturing library.""" """Wrapper for the CP210x manufacturing library."""
def __init__(self, lib_path: Optional[str] = None): def __init__(self, lib_path: str | None = None):
"""Load the CP210x manufacturing library.
Args:
lib_path: Path to libcp210xmanufacturing.so, or None to search default paths.
"""
if lib_path: if lib_path:
self._lib = ctypes.CDLL(lib_path) self._lib = ctypes.CDLL(lib_path)
else: else:
# Search common locations
search_paths = [ search_paths = [
"/usr/lib/libcp210xmanufacturing.so", "/usr/lib/libcp210xmanufacturing.so",
"/usr/local/lib/libcp210xmanufacturing.so", "/usr/local/lib/libcp210xmanufacturing.so",
@ -105,158 +319,198 @@ class CP210xLibrary:
self._setup_functions() self._setup_functions()
def _setup_functions(self): def _setup_functions(self):
"""Set up function prototypes.""" """Set up function prototypes for all library functions."""
# CP210x_GetNumDevices lib = self._lib
self._lib.CP210x_GetNumDevices.argtypes = [POINTER(DWORD)]
self._lib.CP210x_GetNumDevices.restype = CP210x_STATUS
# CP210x_GetProductString # --- Device enumeration ---
self._lib.CP210x_GetProductString.argtypes = [DWORD, c_void_p, DWORD] lib.CP210x_GetNumDevices.argtypes = [POINTER(DWORD)]
self._lib.CP210x_GetProductString.restype = CP210x_STATUS lib.CP210x_GetNumDevices.restype = CP210x_STATUS
# CP210x_Open lib.CP210x_GetProductString.argtypes = [DWORD, c_void_p, DWORD]
self._lib.CP210x_Open.argtypes = [DWORD, POINTER(HANDLE)] lib.CP210x_GetProductString.restype = CP210x_STATUS
self._lib.CP210x_Open.restype = CP210x_STATUS
# CP210x_Close lib.CP210x_Open.argtypes = [DWORD, POINTER(HANDLE)]
self._lib.CP210x_Close.argtypes = [HANDLE] lib.CP210x_Open.restype = CP210x_STATUS
self._lib.CP210x_Close.restype = CP210x_STATUS
# CP210x_GetPartNumber lib.CP210x_Close.argtypes = [HANDLE]
self._lib.CP210x_GetPartNumber.argtypes = [HANDLE, POINTER(BYTE)] lib.CP210x_Close.restype = CP210x_STATUS
self._lib.CP210x_GetPartNumber.restype = CP210x_STATUS
# CP210x_GetDeviceVid # --- Getters (scalars) ---
self._lib.CP210x_GetDeviceVid.argtypes = [HANDLE, POINTER(WORD)] lib.CP210x_GetPartNumber.argtypes = [HANDLE, POINTER(BYTE)]
self._lib.CP210x_GetDeviceVid.restype = CP210x_STATUS lib.CP210x_GetPartNumber.restype = CP210x_STATUS
# CP210x_GetDevicePid lib.CP210x_GetDeviceVid.argtypes = [HANDLE, POINTER(WORD)]
self._lib.CP210x_GetDevicePid.argtypes = [HANDLE, POINTER(WORD)] lib.CP210x_GetDeviceVid.restype = CP210x_STATUS
self._lib.CP210x_GetDevicePid.restype = CP210x_STATUS
# CP210x_GetDeviceManufacturerString lib.CP210x_GetDevicePid.argtypes = [HANDLE, POINTER(WORD)]
self._lib.CP210x_GetDeviceManufacturerString.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL] lib.CP210x_GetDevicePid.restype = CP210x_STATUS
self._lib.CP210x_GetDeviceManufacturerString.restype = CP210x_STATUS
# CP210x_GetDeviceProductString lib.CP210x_GetDeviceManufacturerString.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL]
self._lib.CP210x_GetDeviceProductString.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL] lib.CP210x_GetDeviceManufacturerString.restype = CP210x_STATUS
self._lib.CP210x_GetDeviceProductString.restype = CP210x_STATUS
# CP210x_GetDeviceSerialNumber lib.CP210x_GetDeviceProductString.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL]
self._lib.CP210x_GetDeviceSerialNumber.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL] lib.CP210x_GetDeviceProductString.restype = CP210x_STATUS
self._lib.CP210x_GetDeviceSerialNumber.restype = CP210x_STATUS
# CP210x_SetManufacturerString lib.CP210x_GetDeviceSerialNumber.argtypes = [HANDLE, c_void_p, POINTER(BYTE), BOOL]
self._lib.CP210x_SetManufacturerString.argtypes = [HANDLE, c_void_p, BYTE, BOOL] lib.CP210x_GetDeviceSerialNumber.restype = CP210x_STATUS
self._lib.CP210x_SetManufacturerString.restype = CP210x_STATUS
# CP210x_SetProductString lib.CP210x_GetDeviceInterfaceString.argtypes = [HANDLE, BYTE, c_void_p, POINTER(BYTE), BOOL]
self._lib.CP210x_SetProductString.argtypes = [HANDLE, c_void_p, BYTE, BOOL] lib.CP210x_GetDeviceInterfaceString.restype = CP210x_STATUS
self._lib.CP210x_SetProductString.restype = CP210x_STATUS
# CP210x_SetSerialNumber lib.CP210x_GetMaxPower.argtypes = [HANDLE, POINTER(BYTE)]
self._lib.CP210x_SetSerialNumber.argtypes = [HANDLE, c_void_p, BYTE, BOOL] lib.CP210x_GetMaxPower.restype = CP210x_STATUS
self._lib.CP210x_SetSerialNumber.restype = CP210x_STATUS
# CP210x_GetMaxPower lib.CP210x_GetSelfPower.argtypes = [HANDLE, POINTER(BOOL)]
self._lib.CP210x_GetMaxPower.argtypes = [HANDLE, POINTER(BYTE)] lib.CP210x_GetSelfPower.restype = CP210x_STATUS
self._lib.CP210x_GetMaxPower.restype = CP210x_STATUS
# CP210x_SetMaxPower lib.CP210x_GetDeviceVersion.argtypes = [HANDLE, POINTER(WORD)]
self._lib.CP210x_SetMaxPower.argtypes = [HANDLE, BYTE] lib.CP210x_GetDeviceVersion.restype = CP210x_STATUS
self._lib.CP210x_SetMaxPower.restype = CP210x_STATUS
# CP210x_GetSelfPower lib.CP210x_GetFlushBufferConfig.argtypes = [HANDLE, POINTER(WORD)]
self._lib.CP210x_GetSelfPower.argtypes = [HANDLE, POINTER(BOOL)] lib.CP210x_GetFlushBufferConfig.restype = CP210x_STATUS
self._lib.CP210x_GetSelfPower.restype = CP210x_STATUS
# CP210x_SetSelfPower lib.CP210x_GetDeviceMode.argtypes = [HANDLE, POINTER(BYTE), POINTER(BYTE)]
self._lib.CP210x_SetSelfPower.argtypes = [HANDLE, BOOL] lib.CP210x_GetDeviceMode.restype = CP210x_STATUS
self._lib.CP210x_SetSelfPower.restype = CP210x_STATUS
# CP210x_GetDeviceVersion lib.CP210x_GetLockValue.argtypes = [HANDLE, POINTER(BYTE)]
self._lib.CP210x_GetDeviceVersion.argtypes = [HANDLE, POINTER(WORD)] lib.CP210x_GetLockValue.restype = CP210x_STATUS
self._lib.CP210x_GetDeviceVersion.restype = CP210x_STATUS
# CP210x_SetDeviceVersion lib.CP210x_GetFirmwareVersion.argtypes = [HANDLE, POINTER(FIRMWARE_T)]
self._lib.CP210x_SetDeviceVersion.argtypes = [HANDLE, WORD] lib.CP210x_GetFirmwareVersion.restype = CP210x_STATUS
self._lib.CP210x_SetDeviceVersion.restype = CP210x_STATUS
# CP210x_GetLockValue # --- Setters (scalars) ---
self._lib.CP210x_GetLockValue.argtypes = [HANDLE, POINTER(BYTE)] lib.CP210x_SetVid.argtypes = [HANDLE, WORD]
self._lib.CP210x_GetLockValue.restype = CP210x_STATUS lib.CP210x_SetVid.restype = CP210x_STATUS
# CP210x_SetLockValue lib.CP210x_SetPid.argtypes = [HANDLE, WORD]
self._lib.CP210x_SetLockValue.argtypes = [HANDLE] lib.CP210x_SetPid.restype = CP210x_STATUS
self._lib.CP210x_SetLockValue.restype = CP210x_STATUS
# CP210x_Reset lib.CP210x_SetManufacturerString.argtypes = [HANDLE, c_void_p, BYTE, BOOL]
self._lib.CP210x_Reset.argtypes = [HANDLE] lib.CP210x_SetManufacturerString.restype = CP210x_STATUS
self._lib.CP210x_Reset.restype = CP210x_STATUS
lib.CP210x_SetProductString.argtypes = [HANDLE, c_void_p, BYTE, BOOL]
lib.CP210x_SetProductString.restype = CP210x_STATUS
lib.CP210x_SetSerialNumber.argtypes = [HANDLE, c_void_p, BYTE, BOOL]
lib.CP210x_SetSerialNumber.restype = CP210x_STATUS
lib.CP210x_SetInterfaceString.argtypes = [HANDLE, BYTE, c_void_p, BYTE, BOOL]
lib.CP210x_SetInterfaceString.restype = CP210x_STATUS
lib.CP210x_SetMaxPower.argtypes = [HANDLE, BYTE]
lib.CP210x_SetMaxPower.restype = CP210x_STATUS
lib.CP210x_SetSelfPower.argtypes = [HANDLE, BOOL]
lib.CP210x_SetSelfPower.restype = CP210x_STATUS
lib.CP210x_SetDeviceVersion.argtypes = [HANDLE, WORD]
lib.CP210x_SetDeviceVersion.restype = CP210x_STATUS
lib.CP210x_SetFlushBufferConfig.argtypes = [HANDLE, WORD]
lib.CP210x_SetFlushBufferConfig.restype = CP210x_STATUS
lib.CP210x_SetDeviceMode.argtypes = [HANDLE, BYTE, BYTE]
lib.CP210x_SetDeviceMode.restype = CP210x_STATUS
lib.CP210x_SetLockValue.argtypes = [HANDLE]
lib.CP210x_SetLockValue.restype = CP210x_STATUS
# --- Struct-based configs ---
lib.CP210x_GetBaudRateConfig.argtypes = [HANDLE, POINTER(BAUD_CONFIG)]
lib.CP210x_GetBaudRateConfig.restype = CP210x_STATUS
lib.CP210x_SetBaudRateConfig.argtypes = [HANDLE, POINTER(BAUD_CONFIG)]
lib.CP210x_SetBaudRateConfig.restype = CP210x_STATUS
lib.CP210x_GetPortConfig.argtypes = [HANDLE, POINTER(PORT_CONFIG)]
lib.CP210x_GetPortConfig.restype = CP210x_STATUS
lib.CP210x_SetPortConfig.argtypes = [HANDLE, POINTER(PORT_CONFIG)]
lib.CP210x_SetPortConfig.restype = CP210x_STATUS
lib.CP210x_GetDualPortConfig.argtypes = [HANDLE, POINTER(DUAL_PORT_CONFIG)]
lib.CP210x_GetDualPortConfig.restype = CP210x_STATUS
lib.CP210x_SetDualPortConfig.argtypes = [HANDLE, POINTER(DUAL_PORT_CONFIG)]
lib.CP210x_SetDualPortConfig.restype = CP210x_STATUS
lib.CP210x_GetQuadPortConfig.argtypes = [HANDLE, POINTER(QUAD_PORT_CONFIG)]
lib.CP210x_GetQuadPortConfig.restype = CP210x_STATUS
lib.CP210x_SetQuadPortConfig.argtypes = [HANDLE, POINTER(QUAD_PORT_CONFIG)]
lib.CP210x_SetQuadPortConfig.restype = CP210x_STATUS
# --- Advanced / raw ---
lib.CP210x_GetConfig.argtypes = [HANDLE, POINTER(BYTE), WORD]
lib.CP210x_GetConfig.restype = CP210x_STATUS
lib.CP210x_SetConfig.argtypes = [HANDLE, POINTER(BYTE), WORD]
lib.CP210x_SetConfig.restype = CP210x_STATUS
lib.CP210x_GetGeneric.argtypes = [HANDLE, POINTER(BYTE), WORD]
lib.CP210x_GetGeneric.restype = CP210x_STATUS
lib.CP210x_SetGeneric.argtypes = [HANDLE, POINTER(BYTE), WORD]
lib.CP210x_SetGeneric.restype = CP210x_STATUS
lib.CP210x_CreateHexFile.argtypes = [HANDLE, c_char_p]
lib.CP210x_CreateHexFile.restype = CP210x_STATUS
lib.CP210x_UpdateFirmware.argtypes = [HANDLE]
lib.CP210x_UpdateFirmware.restype = CP210x_STATUS
lib.CP210x_Reset.argtypes = [HANDLE]
lib.CP210x_Reset.restype = CP210x_STATUS
def _check_status(self, status: int, context: str = ""): def _check_status(self, status: int, context: str = ""):
"""Raise exception if status indicates error."""
if status != CP210x_SUCCESS: if status != CP210x_SUCCESS:
raise CP210xError(status, context) raise CP210xError(status, context)
# --- Device enumeration ---
def get_num_devices(self) -> int: def get_num_devices(self) -> int:
"""Get the number of connected CP210x devices."""
num = DWORD() num = DWORD()
status = self._lib.CP210x_GetNumDevices(byref(num)) status = self._lib.CP210x_GetNumDevices(byref(num))
self._check_status(status, "GetNumDevices") self._check_status(status, "GetNumDevices")
return num.value return num.value
def get_product_string(self, device_index: int, flag: int = RETURN_DESCRIPTION) -> str: def get_product_string(self, device_index: int, flag: int = RETURN_DESCRIPTION) -> str:
"""Get device string without opening the device.
Args:
device_index: Zero-based device index
flag: What to return - RETURN_SERIAL_NUMBER, RETURN_DESCRIPTION, or RETURN_FULL_PATH
"""
buf = ctypes.create_string_buffer(MAX_DEVICE_STRLEN) buf = ctypes.create_string_buffer(MAX_DEVICE_STRLEN)
status = self._lib.CP210x_GetProductString(DWORD(device_index), buf, DWORD(flag)) status = self._lib.CP210x_GetProductString(DWORD(device_index), buf, DWORD(flag))
self._check_status(status, "GetProductString") self._check_status(status, "GetProductString")
return buf.value.decode('utf-8', errors='replace') return buf.value.decode('utf-8', errors='replace')
def open(self, device_index: int) -> HANDLE: def open(self, device_index: int) -> HANDLE:
"""Open a device by index."""
handle = HANDLE() handle = HANDLE()
status = self._lib.CP210x_Open(DWORD(device_index), byref(handle)) status = self._lib.CP210x_Open(DWORD(device_index), byref(handle))
self._check_status(status, f"Open device {device_index}") self._check_status(status, f"Open device {device_index}")
return handle return handle
def close(self, handle: HANDLE): def close(self, handle: HANDLE):
"""Close an open device."""
status = self._lib.CP210x_Close(handle) status = self._lib.CP210x_Close(handle)
self._check_status(status, "Close") self._check_status(status, "Close")
def get_part_number(self, handle: HANDLE) -> tuple[int, str]: # --- Scalar getters ---
"""Get the part number of an open device.
Returns: def get_part_number(self, handle: HANDLE) -> tuple[int, str]:
Tuple of (part_number_code, part_name)
"""
part = BYTE() part = BYTE()
status = self._lib.CP210x_GetPartNumber(handle, byref(part)) status = self._lib.CP210x_GetPartNumber(handle, byref(part))
self._check_status(status, "GetPartNumber") self._check_status(status, "GetPartNumber")
return part.value, PART_NUMBERS.get(part.value, f"Unknown (0x{part.value:02X})") return part.value, PART_NUMBERS.get(part.value, f"Unknown (0x{part.value:02X})")
def get_device_vid(self, handle: HANDLE) -> int: def get_device_vid(self, handle: HANDLE) -> int:
"""Get the USB Vendor ID."""
vid = WORD() vid = WORD()
status = self._lib.CP210x_GetDeviceVid(handle, byref(vid)) status = self._lib.CP210x_GetDeviceVid(handle, byref(vid))
self._check_status(status, "GetDeviceVid") self._check_status(status, "GetDeviceVid")
return vid.value return vid.value
def get_device_pid(self, handle: HANDLE) -> int: def get_device_pid(self, handle: HANDLE) -> int:
"""Get the USB Product ID."""
pid = WORD() pid = WORD()
status = self._lib.CP210x_GetDevicePid(handle, byref(pid)) status = self._lib.CP210x_GetDevicePid(handle, byref(pid))
self._check_status(status, "GetDevicePid") self._check_status(status, "GetDevicePid")
return pid.value return pid.value
def get_manufacturer_string(self, handle: HANDLE) -> str: def get_manufacturer_string(self, handle: HANDLE) -> str:
"""Get the manufacturer string."""
buf = ctypes.create_string_buffer(MAX_MANUFACTURER_STRLEN) buf = ctypes.create_string_buffer(MAX_MANUFACTURER_STRLEN)
length = BYTE() length = BYTE()
status = self._lib.CP210x_GetDeviceManufacturerString(handle, buf, byref(length), BOOL(1)) status = self._lib.CP210x_GetDeviceManufacturerString(handle, buf, byref(length), BOOL(1))
@ -264,7 +518,6 @@ class CP210xLibrary:
return buf.value.decode('utf-8', errors='replace') return buf.value.decode('utf-8', errors='replace')
def get_product_string_device(self, handle: HANDLE) -> str: def get_product_string_device(self, handle: HANDLE) -> str:
"""Get the product string from an open device."""
buf = ctypes.create_string_buffer(MAX_PRODUCT_STRLEN) buf = ctypes.create_string_buffer(MAX_PRODUCT_STRLEN)
length = BYTE() length = BYTE()
status = self._lib.CP210x_GetDeviceProductString(handle, buf, byref(length), BOOL(1)) status = self._lib.CP210x_GetDeviceProductString(handle, buf, byref(length), BOOL(1))
@ -272,88 +525,282 @@ class CP210xLibrary:
return buf.value.decode('utf-8', errors='replace') return buf.value.decode('utf-8', errors='replace')
def get_serial_number(self, handle: HANDLE) -> str: def get_serial_number(self, handle: HANDLE) -> str:
"""Get the serial number."""
buf = ctypes.create_string_buffer(MAX_SERIAL_STRLEN) buf = ctypes.create_string_buffer(MAX_SERIAL_STRLEN)
length = BYTE() length = BYTE()
status = self._lib.CP210x_GetDeviceSerialNumber(handle, buf, byref(length), BOOL(1)) status = self._lib.CP210x_GetDeviceSerialNumber(handle, buf, byref(length), BOOL(1))
self._check_status(status, "GetDeviceSerialNumber") self._check_status(status, "GetDeviceSerialNumber")
return buf.value.decode('utf-8', errors='replace') return buf.value.decode('utf-8', errors='replace')
def set_manufacturer_string(self, handle: HANDLE, manufacturer: str): def get_interface_string(self, handle: HANDLE, interface_number: int) -> str:
"""Set the manufacturer string (max 45 chars).""" buf = ctypes.create_string_buffer(CP2108_MAX_INTERFACE_STRLEN)
data = manufacturer.encode('utf-8')[:MAX_MANUFACTURER_STRLEN] length = BYTE()
status = self._lib.CP210x_SetManufacturerString(handle, data, BYTE(len(data)), BOOL(1)) status = self._lib.CP210x_GetDeviceInterfaceString(
self._check_status(status, "SetManufacturerString") handle, BYTE(interface_number), buf, byref(length), BOOL(1)
)
def set_product_string(self, handle: HANDLE, product: str): self._check_status(status, f"GetDeviceInterfaceString(ifc={interface_number})")
"""Set the product string (max 126 chars).""" return buf.value.decode('utf-8', errors='replace')
data = product.encode('utf-8')[:MAX_PRODUCT_STRLEN]
status = self._lib.CP210x_SetProductString(handle, data, BYTE(len(data)), BOOL(1))
self._check_status(status, "SetProductString")
def set_serial_number(self, handle: HANDLE, serial: str):
"""Set the serial number (max 63 chars)."""
data = serial.encode('utf-8')[:MAX_SERIAL_STRLEN]
status = self._lib.CP210x_SetSerialNumber(handle, data, BYTE(len(data)), BOOL(1))
self._check_status(status, "SetSerialNumber")
def get_max_power(self, handle: HANDLE) -> int: def get_max_power(self, handle: HANDLE) -> int:
"""Get max power in units of 2mA (multiply by 2 for mA)."""
power = BYTE() power = BYTE()
status = self._lib.CP210x_GetMaxPower(handle, byref(power)) status = self._lib.CP210x_GetMaxPower(handle, byref(power))
self._check_status(status, "GetMaxPower") self._check_status(status, "GetMaxPower")
return power.value return power.value
def set_max_power(self, handle: HANDLE, power_2ma: int):
"""Set max power in units of 2mA (e.g., 50 = 100mA)."""
if power_2ma > 250:
raise ValueError("Max power cannot exceed 250 (500mA)")
status = self._lib.CP210x_SetMaxPower(handle, BYTE(power_2ma))
self._check_status(status, "SetMaxPower")
def get_self_power(self, handle: HANDLE) -> bool: def get_self_power(self, handle: HANDLE) -> bool:
"""Check if device is self-powered."""
self_power = BOOL() self_power = BOOL()
status = self._lib.CP210x_GetSelfPower(handle, byref(self_power)) status = self._lib.CP210x_GetSelfPower(handle, byref(self_power))
self._check_status(status, "GetSelfPower") self._check_status(status, "GetSelfPower")
return bool(self_power.value) return bool(self_power.value)
def set_self_power(self, handle: HANDLE, self_powered: bool):
"""Set whether device is self-powered."""
status = self._lib.CP210x_SetSelfPower(handle, BOOL(1 if self_powered else 0))
self._check_status(status, "SetSelfPower")
def get_device_version(self, handle: HANDLE) -> int: def get_device_version(self, handle: HANDLE) -> int:
"""Get device version (bcdDevice)."""
version = WORD() version = WORD()
status = self._lib.CP210x_GetDeviceVersion(handle, byref(version)) status = self._lib.CP210x_GetDeviceVersion(handle, byref(version))
self._check_status(status, "GetDeviceVersion") self._check_status(status, "GetDeviceVersion")
return version.value return version.value
def set_device_version(self, handle: HANDLE, version: int): def get_flush_buffer_config(self, handle: HANDLE) -> int:
"""Set device version (bcdDevice).""" config = WORD()
status = self._lib.CP210x_SetDeviceVersion(handle, WORD(version)) status = self._lib.CP210x_GetFlushBufferConfig(handle, byref(config))
self._check_status(status, "SetDeviceVersion") self._check_status(status, "GetFlushBufferConfig")
return config.value
def get_device_mode(self, handle: HANDLE) -> tuple[int, int]:
eci = BYTE()
sci = BYTE()
status = self._lib.CP210x_GetDeviceMode(handle, byref(eci), byref(sci))
self._check_status(status, "GetDeviceMode")
return eci.value, sci.value
def get_lock_value(self, handle: HANDLE) -> int: def get_lock_value(self, handle: HANDLE) -> int:
"""Get lock value (0 = unlocked, 1-255 = locked)."""
lock = BYTE() lock = BYTE()
status = self._lib.CP210x_GetLockValue(handle, byref(lock)) status = self._lib.CP210x_GetLockValue(handle, byref(lock))
self._check_status(status, "GetLockValue") self._check_status(status, "GetLockValue")
return lock.value return lock.value
def get_firmware_version(self, handle: HANDLE) -> tuple[int, int, int]:
fw = FIRMWARE_T()
status = self._lib.CP210x_GetFirmwareVersion(handle, byref(fw))
self._check_status(status, "GetFirmwareVersion")
return fw.major, fw.minor, fw.build
# --- Scalar setters ---
def set_vid(self, handle: HANDLE, vid: int):
status = self._lib.CP210x_SetVid(handle, WORD(vid))
self._check_status(status, "SetVid")
def set_pid(self, handle: HANDLE, pid: int):
status = self._lib.CP210x_SetPid(handle, WORD(pid))
self._check_status(status, "SetPid")
def set_manufacturer_string(self, handle: HANDLE, manufacturer: str):
data = manufacturer.encode('utf-8')[:MAX_MANUFACTURER_STRLEN]
status = self._lib.CP210x_SetManufacturerString(handle, data, BYTE(len(data)), BOOL(1))
self._check_status(status, "SetManufacturerString")
def set_product_string(self, handle: HANDLE, product: str):
data = product.encode('utf-8')[:MAX_PRODUCT_STRLEN]
status = self._lib.CP210x_SetProductString(handle, data, BYTE(len(data)), BOOL(1))
self._check_status(status, "SetProductString")
def set_serial_number(self, handle: HANDLE, serial: str):
data = serial.encode('utf-8')[:MAX_SERIAL_STRLEN]
status = self._lib.CP210x_SetSerialNumber(handle, data, BYTE(len(data)), BOOL(1))
self._check_status(status, "SetSerialNumber")
def set_interface_string(self, handle: HANDLE, interface_number: int, value: str):
data = value.encode('utf-8')[:CP2108_MAX_INTERFACE_STRLEN]
status = self._lib.CP210x_SetInterfaceString(
handle, BYTE(interface_number), data, BYTE(len(data)), BOOL(1)
)
self._check_status(status, f"SetInterfaceString(ifc={interface_number})")
def set_max_power(self, handle: HANDLE, power_2ma: int):
if power_2ma > 250:
raise ValueError("Max power cannot exceed 250 (500mA)")
status = self._lib.CP210x_SetMaxPower(handle, BYTE(power_2ma))
self._check_status(status, "SetMaxPower")
def set_self_power(self, handle: HANDLE, self_powered: bool):
status = self._lib.CP210x_SetSelfPower(handle, BOOL(1 if self_powered else 0))
self._check_status(status, "SetSelfPower")
def set_device_version(self, handle: HANDLE, version: int):
status = self._lib.CP210x_SetDeviceVersion(handle, WORD(version))
self._check_status(status, "SetDeviceVersion")
def set_flush_buffer_config(self, handle: HANDLE, config: int):
status = self._lib.CP210x_SetFlushBufferConfig(handle, WORD(config))
self._check_status(status, "SetFlushBufferConfig")
def set_device_mode(self, handle: HANDLE, eci_mode: int, sci_mode: int):
status = self._lib.CP210x_SetDeviceMode(handle, BYTE(eci_mode), BYTE(sci_mode))
self._check_status(status, "SetDeviceMode")
def lock_device(self, handle: HANDLE): def lock_device(self, handle: HANDLE):
"""Lock the device (PERMANENT - cannot be undone!)."""
status = self._lib.CP210x_SetLockValue(handle) status = self._lib.CP210x_SetLockValue(handle)
self._check_status(status, "SetLockValue") self._check_status(status, "SetLockValue")
# --- Struct-based configs ---
def get_baud_rate_config(self, handle: HANDLE) -> list[dict]:
data = BAUD_CONFIG_DATA()
status = self._lib.CP210x_GetBaudRateConfig(handle, data)
self._check_status(status, "GetBaudRateConfig")
return [
{
"index": i,
"baud_gen": data[i].BaudGen,
"timer0_reload": data[i].Timer0Reload,
"prescaler": data[i].Prescaler,
"baud_rate": data[i].BaudRate,
}
for i in range(NUM_BAUD_CONFIGS)
]
def set_baud_rate_config(self, handle: HANDLE, configs: list[dict]):
if len(configs) != NUM_BAUD_CONFIGS:
raise ValueError(f"Expected {NUM_BAUD_CONFIGS} baud configs, got {len(configs)}")
data = BAUD_CONFIG_DATA()
for i, cfg in enumerate(configs):
data[i].BaudGen = cfg["baud_gen"]
data[i].Timer0Reload = cfg["timer0_reload"]
data[i].Prescaler = cfg["prescaler"]
data[i]._pad = 0
data[i].BaudRate = cfg["baud_rate"]
status = self._lib.CP210x_SetBaudRateConfig(handle, data)
self._check_status(status, "SetBaudRateConfig")
def get_port_config(self, handle: HANDLE) -> dict:
cfg = PORT_CONFIG()
status = self._lib.CP210x_GetPortConfig(handle, byref(cfg))
self._check_status(status, "GetPortConfig")
return {
"mode": cfg.Mode,
"reset_latch": cfg.Reset_Latch,
"suspend_latch": cfg.Suspend_Latch,
"enhanced_fxn": cfg.EnhancedFxn,
}
def set_port_config(self, handle: HANDLE, mode: int, reset_latch: int, suspend_latch: int, enhanced_fxn: int):
cfg = PORT_CONFIG()
cfg.Mode = mode
cfg.Reset_Latch = reset_latch
cfg.Suspend_Latch = suspend_latch
cfg.EnhancedFxn = enhanced_fxn
status = self._lib.CP210x_SetPortConfig(handle, byref(cfg))
self._check_status(status, "SetPortConfig")
def get_dual_port_config(self, handle: HANDLE) -> dict:
cfg = DUAL_PORT_CONFIG()
status = self._lib.CP210x_GetDualPortConfig(handle, byref(cfg))
self._check_status(status, "GetDualPortConfig")
return {
"mode": cfg.Mode,
"reset_latch": cfg.Reset_Latch,
"suspend_latch": cfg.Suspend_Latch,
"enhanced_fxn_eci": cfg.EnhancedFxn_ECI,
"enhanced_fxn_sci": cfg.EnhancedFxn_SCI,
"enhanced_fxn_device": cfg.EnhancedFxn_Device,
}
def set_dual_port_config(self, handle: HANDLE, mode: int, reset_latch: int,
suspend_latch: int, enhanced_fxn_eci: int,
enhanced_fxn_sci: int, enhanced_fxn_device: int):
cfg = DUAL_PORT_CONFIG()
cfg.Mode = mode
cfg.Reset_Latch = reset_latch
cfg.Suspend_Latch = suspend_latch
cfg.EnhancedFxn_ECI = enhanced_fxn_eci
cfg.EnhancedFxn_SCI = enhanced_fxn_sci
cfg.EnhancedFxn_Device = enhanced_fxn_device
status = self._lib.CP210x_SetDualPortConfig(handle, byref(cfg))
self._check_status(status, "SetDualPortConfig")
def _quad_port_state_to_dict(self, qps: QUAD_PORT_STATE) -> dict:
return {
f"pb{i}": {"mode": getattr(qps, f"Mode_PB{i}"),
"low_power": getattr(qps, f"LowPower_PB{i}"),
"latch": getattr(qps, f"Latch_PB{i}")}
for i in range(5)
}
def get_quad_port_config(self, handle: HANDLE) -> dict:
cfg = QUAD_PORT_CONFIG()
status = self._lib.CP210x_GetQuadPortConfig(handle, byref(cfg))
self._check_status(status, "GetQuadPortConfig")
return {
"reset_latch": self._quad_port_state_to_dict(cfg.Reset_Latch),
"suspend_latch": self._quad_port_state_to_dict(cfg.Suspend_Latch),
"ip_delay": [cfg.IPDelay_IFC0, cfg.IPDelay_IFC1, cfg.IPDelay_IFC2, cfg.IPDelay_IFC3],
"enhanced_fxn": [cfg.EnhancedFxn_IFC0, cfg.EnhancedFxn_IFC1,
cfg.EnhancedFxn_IFC2, cfg.EnhancedFxn_IFC3],
"enhanced_fxn_device": cfg.EnhancedFxn_Device,
"ext_clk_freq": [cfg.ExtClk0Freq, cfg.ExtClk1Freq,
cfg.ExtClk2Freq, cfg.ExtClk3Freq],
}
def set_quad_port_config(self, handle: HANDLE, config_dict: dict):
cfg = QUAD_PORT_CONFIG()
for state_name in ("reset_latch", "suspend_latch"):
state = getattr(cfg, state_name.title().replace("_l", "_L"))
src = config_dict[state_name]
for i in range(5):
pb = src[f"pb{i}"]
setattr(state, f"Mode_PB{i}", pb["mode"])
setattr(state, f"LowPower_PB{i}", pb["low_power"])
setattr(state, f"Latch_PB{i}", pb["latch"])
for i in range(4):
setattr(cfg, f"IPDelay_IFC{i}", config_dict["ip_delay"][i])
setattr(cfg, f"EnhancedFxn_IFC{i}", config_dict["enhanced_fxn"][i])
cfg.EnhancedFxn_Device = config_dict["enhanced_fxn_device"]
for i in range(4):
setattr(cfg, f"ExtClk{i}Freq", config_dict["ext_clk_freq"][i])
status = self._lib.CP210x_SetQuadPortConfig(handle, byref(cfg))
self._check_status(status, "SetQuadPortConfig")
# --- Advanced / raw ---
def get_config(self, handle: HANDLE, size: int = 512) -> bytes:
buf = (BYTE * size)()
status = self._lib.CP210x_GetConfig(handle, buf, WORD(size))
self._check_status(status, "GetConfig")
return bytes(buf)
def set_config(self, handle: HANDLE, data: bytes):
buf = (BYTE * len(data))(*data)
status = self._lib.CP210x_SetConfig(handle, buf, WORD(len(data)))
self._check_status(status, "SetConfig")
def get_generic(self, handle: HANDLE, size: int = 512) -> bytes:
buf = (BYTE * size)()
status = self._lib.CP210x_GetGeneric(handle, buf, WORD(size))
self._check_status(status, "GetGeneric")
return bytes(buf)
def set_generic(self, handle: HANDLE, data: bytes):
buf = (BYTE * len(data))(*data)
status = self._lib.CP210x_SetGeneric(handle, buf, WORD(len(data)))
self._check_status(status, "SetGeneric")
def create_hex_file(self, handle: HANDLE, filename: str):
status = self._lib.CP210x_CreateHexFile(handle, filename.encode('utf-8'))
self._check_status(status, "CreateHexFile")
def update_firmware(self, handle: HANDLE):
status = self._lib.CP210x_UpdateFirmware(handle)
self._check_status(status, "UpdateFirmware")
def reset(self, handle: HANDLE): def reset(self, handle: HANDLE):
"""Reset the device (USB disconnect/reconnect)."""
status = self._lib.CP210x_Reset(handle) status = self._lib.CP210x_Reset(handle)
self._check_status(status, "Reset") self._check_status(status, "Reset")
# Convenience context manager for device access
class CP210xDevice: class CP210xDevice:
"""Context manager for safe device access.""" """Context manager for safe device access."""
@ -361,6 +808,7 @@ class CP210xDevice:
self.lib = lib self.lib = lib
self.device_index = device_index self.device_index = device_index
self.handle = None self.handle = None
self._part_code: int | None = None
def __enter__(self): def __enter__(self):
self.handle = self.lib.open(self.device_index) self.handle = self.lib.open(self.device_index)
@ -372,6 +820,21 @@ class CP210xDevice:
self.handle = None self.handle = None
return False return False
def _get_part_code(self) -> int:
if self._part_code is None:
self._part_code = self.lib.get_part_number(self.handle)[0]
return self._part_code
def _require_part(self, allowed: set[int], feature: str):
code = self._get_part_code()
if code not in allowed:
name = PART_NUMBERS.get(code, f"0x{code:02X}")
allowed_names = ", ".join(PART_NUMBERS.get(c, f"0x{c:02X}") for c in sorted(allowed))
raise CP210xError(
CP210x_FUNCTION_NOT_SUPPORTED,
f"{feature} not supported on {name} (requires {allowed_names})",
)
@property @property
def part_number(self) -> tuple[int, str]: def part_number(self) -> tuple[int, str]:
return self.lib.get_part_number(self.handle) return self.lib.get_part_number(self.handle)
@ -410,12 +873,10 @@ class CP210xDevice:
@property @property
def max_power_ma(self) -> int: def max_power_ma(self) -> int:
"""Max power in milliamps."""
return self.lib.get_max_power(self.handle) * 2 return self.lib.get_max_power(self.handle) * 2
@max_power_ma.setter @max_power_ma.setter
def max_power_ma(self, value: int): def max_power_ma(self, value: int):
"""Set max power in milliamps (will be rounded down to nearest 2mA)."""
self.lib.set_max_power(self.handle, value // 2) self.lib.set_max_power(self.handle, value // 2)
@property @property
@ -428,14 +889,49 @@ class CP210xDevice:
@property @property
def device_version(self) -> str: def device_version(self) -> str:
"""Device version as BCD string (e.g., '1.00')."""
v = self.lib.get_device_version(self.handle) v = self.lib.get_device_version(self.handle)
return f"{(v >> 8) & 0xFF}.{v & 0xFF:02d}" return f"{(v >> 8) & 0xFF}.{v & 0xFF:02d}"
@device_version.setter
def device_version(self, value: int):
self.lib.set_device_version(self.handle, value)
@property @property
def is_locked(self) -> bool: def is_locked(self) -> bool:
return self.lib.get_lock_value(self.handle) != 0 return self.lib.get_lock_value(self.handle) != 0
@property
def firmware_version(self) -> str | None:
"""Firmware version string (CP2102N only). Returns None if not supported."""
try:
major, minor, build = self.lib.get_firmware_version(self.handle)
return f"{major}.{minor}.{build}"
except CP210xError:
return None
@property
def flush_buffer_config(self) -> int | None:
"""Raw flush buffer config word. Returns None if not supported."""
try:
return self.lib.get_flush_buffer_config(self.handle)
except CP210xError:
return None
@property
def device_mode(self) -> tuple[int, int] | None:
"""(ECI mode, SCI mode) for CP2105. Returns None if not supported."""
try:
return self.lib.get_device_mode(self.handle)
except CP210xError:
return None
def get_interface_string(self, interface_number: int) -> str:
self._require_part(PARTS_WITH_INTERFACE_STRING, "Interface strings")
return self.lib.get_interface_string(self.handle, interface_number)
def set_interface_string(self, interface_number: int, value: str):
self._require_part(PARTS_WITH_INTERFACE_STRING, "Interface strings")
self.lib.set_interface_string(self.handle, interface_number, value)
def reset(self): def reset(self):
"""Reset the device."""
self.lib.reset(self.handle) self.lib.reset(self.handle)

File diff suppressed because it is too large Load Diff