Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support CY6C65215 and CY6C65215A #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 91 additions & 64 deletions src/cy_serial_bridge/cy_scb_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,63 @@ def _find_serial_port_name_for_serno(serial_number: str) -> str | None:

return None



def identify_interface(self, intf: usb1.USBInterface) -> CyType|None:
"""
Identify the current interface of a device.

This is useful for determining the current mode of a device, as the interface is the only part of the device
that can be queried without opening it.
"""
if intf[0].getClass() == USBClass.CDC:
if intf[0].getSubClass() == 0x2:
return CyType.UART_CDC
# elif intf[0].getSubClass() == ??
# return CyType.SPI_CDC
elif intf[0].getClass() == 0x0A:
if intf[0].getSubClass() == 0x0:
return CyType.CDC_DATA
elif intf[0].getClass() == 0xFF:
# Check manufacturer interface.
# It has a defined class/subclass and has no endpoints
if intf[0].getNumEndpoints() != 0:
return None
if intf[0].getSubClass() == CyType.MFG:
return CyType.MFG
elif intf[0].getClass() == USBClass.VENDOR:
if intf[0].getSubClass() not in {
CyType.UART_VENDOR.value,
CyType.SPI.value,
CyType.I2C.value,
CyType.JTAG.value,
}:
return None
if intf[0].getNumEndpoints() != 3:
return None
# Bulk host-to-dev endpoint
if (
not (intf[0].getAddress() in [0x01, 0x04])
or (intf[0].getAttributes() & 0x3) != 2
):
return None
# Bulk dev-to-host endpoint
if (
not (intf[1].getAddress() in [0x82, 0x85])
or (intf[1].getAttributes() & 0x3) != 2
):
return None
# Interrupt dev-to-host endpoint
if (
not (intf[2].getAddress() in [0x83, 0x86])
or (intf[2].getAttributes() & 0x3) != 3
):
return None
return CyType(intf[0].getSubClass())
return None



def list_devices(
self,
vid_pids: Set[tuple[int, int]] | None = DEFAULT_VIDS_PIDS,
Expand Down Expand Up @@ -110,79 +167,49 @@ def list_devices(

# CY7C652xx devices always have either two or three interfaces: potentially one for the USB CDC COM port,
# one for the actual USB-serial bridge, and one for the configuration interface.
if cfg.getNumInterfaces() != 2 and cfg.getNumInterfaces() != 3:
# CY7C65215 and CY7C65215A devices have (up to?) 4 interfaces.
# CY7C65215 devices could have 0-2 CDC interfaces, up to one on each SCB
if cfg.getNumInterfaces() != 2 and cfg.getNumInterfaces() != 3 and cfg.getNumInterfaces() != 4:
continue

usb_cdc_interface_settings: usb1.USBInterfaceSetting | None = None
cdc_data_interface_settings: usb1.USBInterfaceSetting | None = None
scb_interface_settings: usb1.USBInterfaceSetting | None = None
mfg_interface_settings: usb1.USBInterfaceSetting

if cfg.getNumInterfaces() == 3 and cfg[0][0].getClass() == USBClass.CDC:
# USB CDC mode
usb_cdc_interface_settings = cfg[0][0]
cdc_data_interface_settings = cfg[1][0]
mfg_interface_settings = cfg[2][0]

# Check USB CDC interface
if usb_cdc_interface_settings.getSubClass() != 0x2:
continue

# Check CDC Data interface
if cdc_data_interface_settings.getClass() != 0x0A or cdc_data_interface_settings.getSubClass() != 0x0:
continue

curr_cytype = CyType.UART_CDC

else:
# USB vendor mode
scb_interface_settings = cfg[0][0]
mfg_interface_settings = cfg[1][0]

# Check SCB interface -- the Class should be 0xFF (vendor defined/no rules)
# and the SubClass value gives the CyType
if scb_interface_settings.getClass() != USBClass.VENDOR:
continue
if scb_interface_settings.getSubClass() not in {
CyType.UART_VENDOR.value,
CyType.SPI.value,
CyType.I2C.value,
}:
continue

# Check SCB endpoints
if scb_interface_settings.getNumEndpoints() != 3:
continue
# Bulk host-to-dev endpoint
if (
scb_interface_settings[0].getAddress() != 0x01
or (scb_interface_settings[0].getAttributes() & 0x3) != 2
):
continue
# Bulk dev-to-host endpoint
if (
scb_interface_settings[1].getAddress() != 0x82
or (scb_interface_settings[1].getAttributes() & 0x3) != 2
):
continue
# Interrupt dev-to-host endpoint
if (
scb_interface_settings[2].getAddress() != 0x83
or (scb_interface_settings[2].getAttributes() & 0x3) != 3
):
continue

curr_cytype = CyType(scb_interface_settings.getSubClass())

# Check manufacturer interface.
# It has a defined class/subclass and has no endpoints
if mfg_interface_settings.getClass() != 0xFF:
continue
if mfg_interface_settings.getSubClass() != CyType.MFG:
continue
if mfg_interface_settings.getNumEndpoints() != 0:
for i in range(cfg.getNumInterfaces()):
type = self.identify_interface(cfg[i])
if type == None:
pass # TODO verbose output
else:
match(type):
case CyType.UART_CDC: # TODO we could have two of these!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to handle this case a little bit better in this function. I think what would make sense would be to add two DiscoveredDevice entries to the output when we see a dual channel device. Either that, or make DiscoveredDevice able to hold two different channels from one device.

usb_cdc_interface_settings = cfg[i][0]
curr_cytype = CyType.UART_CDC
case CyType.CDC_DATA:
cdc_data_interface_settings = cfg[i][0]
case CyType.MFG:
mfg_interface_settings = cfg[i][0]
case CyType.I2C: # TODO we could have two of these!
scb_interface_settings = cfg[i][0]
curr_cytype = CyType.I2C
case CyType.SPI:
scb_interface_settings = cfg[i][0]
curr_cytype = CyType.SPI
case CyType.JTAG:
scb_interface_settings = cfg[i][0]
curr_cytype = CyType.JTAG
case CyType.UART_VENDOR:
scb_interface_settings = cfg[i][0]
curr_cytype = CyType.UART_VENDOR

if curr_cytype is None or mfg_interface_settings is None \
or (scb_interface_settings is None and usb_cdc_interface_settings is None):
# TODO verbose output
continue

if mfg_interface_settings is not None: curr_cytype = CyType.MFG

# If we got all the way here, it looks like a CY6C652xx device!
# Record attributes and add it to the list
list_entry = DiscoveredDevice(
Expand Down
1 change: 1 addition & 0 deletions src/cy_serial_bridge/usb_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class CyType(IntEnum):
6 # Used to indicate a device which is in CDC UART mode (which will automatically work using an OS driver)
)
UART_PHDC = 7 # Used to indicate a device which is in PHDC (Personal Healthcare Device Class) UART mode
CDC_DATA = 8 # Used to indicate the CDC data interface (which is a separate interface from the CDC UART interface)


class CyVendorCmds(IntEnum):
Expand Down