Skip to content

Commit

Permalink
Add ability to add more constraints to bdDetect USB device registrati…
Browse files Browse the repository at this point in the history
…on (#17537)

Fixes #17521

Summary of the issue:
In several cases, registering a USB device in bdDetect with just VID and PID is not enough. We need an extra filter to ensure that only the right devices are detected. This was fixed at the driver level until now, but fixing this in bdDetect improves performance and stability.

Description of user facing changes
More stability and quicker detection times.

Description of development approach
Added the ability to register a match func that further constraints device detection for specific VID/PID combinations.
  • Loading branch information
LeonarddeR authored Jan 3, 2025
1 parent 4bab722 commit a7fa0d6
Show file tree
Hide file tree
Showing 18 changed files with 276 additions and 137 deletions.
231 changes: 167 additions & 64 deletions source/bdDetect.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion source/braille.py
Original file line number Diff line number Diff line change
Expand Up @@ -3517,7 +3517,7 @@ def _getTryPorts(
pass
else:
yield bdDetect.DeviceMatch(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
portInfo["bluetoothName" if "bluetoothName" in portInfo else "friendlyName"],
portInfo["port"],
portInfo,
Expand Down
17 changes: 6 additions & 11 deletions source/brailleDisplayDrivers/albatross/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import time

from collections import deque
from bdDetect import DeviceType, DriverRegistrar
from bdDetect import DriverRegistrar, ProtocolType
from logHandler import log
from serial.win32 import (
PURGE_RXABORT,
Expand Down Expand Up @@ -84,11 +84,11 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):

@classmethod
def registerAutomaticDetection(cls, driverRegistrar: DriverRegistrar):
driverRegistrar.addUsbDevices(
DeviceType.SERIAL,
{
"VID_0403&PID_6001", # Caiku Albatross 46/80
},
driverRegistrar.addUsbDevice(
ProtocolType.SERIAL,
VID_AND_PID, # Caiku Albatross 46/80
# Filter for bus reported device description, which should be "Albatross Braille Display".
matchFunc=lambda match: match.deviceInfo.get("busReportedDeviceDescription") == BUS_DEVICE_DESC,
)

@classmethod
Expand Down Expand Up @@ -168,11 +168,6 @@ def _searchPorts(self, originalPort: str):
"""
for self._baudRate in BAUD_RATE:
for portType, portId, port, portInfo in self._getTryPorts(originalPort):
# Block port if its vid and pid are correct but bus reported
# device description is not "Albatross Braille Display".
if portId == VID_AND_PID and portInfo.get("busReportedDeviceDescription") != BUS_DEVICE_DESC:
log.debug(f"port {port} blocked; port information: {portInfo}")
continue
# For reconnection
self._currentPort = port
self._tryToConnect = True
Expand Down
4 changes: 2 additions & 2 deletions source/brailleDisplayDrivers/alva.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_0798&PID_0640", # BC640
"VID_0798&PID_0680", # BC680
Expand Down Expand Up @@ -216,7 +216,7 @@ def __init__(self, port="auto"):
self._deviceId = None

for portType, portId, port, portInfo in self._getTryPorts(port):
self.isHid = portType == bdDetect.DeviceType.HID
self.isHid = portType == bdDetect.ProtocolType.HID
# Try talking to the display.
try:
if self.isHid:
Expand Down
6 changes: 3 additions & 3 deletions source/brailleDisplayDrivers/baum.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_0904&PID_3001", # RefreshaBraille 18
"VID_0904&PID_6101", # VarioUltra 20
Expand All @@ -111,7 +111,7 @@ def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
)

driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_0403&PID_FE70", # Vario 40
"VID_0403&PID_FE71", # PocketVario
Expand Down Expand Up @@ -164,7 +164,7 @@ def __init__(self, port="auto"):
for portType, portId, port, portInfo in self._getTryPorts(port):
# At this point, a port bound to this display has been found.
# Try talking to the display.
self.isHid = portType == bdDetect.DeviceType.HID
self.isHid = portType == bdDetect.ProtocolType.HID
try:
if self.isHid:
self._dev = hwIo.Hid(port, onReceive=self._onReceive)
Expand Down
2 changes: 1 addition & 1 deletion source/brailleDisplayDrivers/brailleNote.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_1C71&PID_C004", # Apex
},
Expand Down
49 changes: 32 additions & 17 deletions source/brailleDisplayDrivers/brailliantB.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
HR_KEYS = b"\x04"
HR_BRAILLE = b"\x05"
HR_POWEROFF = b"\x07"
HID_USAGE_PAGE = 0x93

KEY_NAMES = {
1: "power", # Brailliant BI 32, 40 and 80.
Expand Down Expand Up @@ -89,47 +90,61 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_1C71&PID_C111", # Mantis Q 40
"VID_1C71&PID_C101", # Chameleon 20
"VID_1C71&PID_C131", # Brailliant BI 40X
"VID_1C71&PID_C141", # Brailliant BI 20X
},
matchFunc=bdDetect.HIDUsagePageMatchFuncFactory(HID_USAGE_PAGE),
)
driverRegistrar.addUsbDevices(
bdDetect.ProtocolType.HID,
{
"VID_1C71&PID_C121", # Humanware BrailleOne 20 HID
"VID_1C71&PID_CE01", # NLS eReader 20 HID
"VID_1C71&PID_C006", # Brailliant BI 32, 40 and 80
"VID_1C71&PID_C022", # Brailliant BI 14
"VID_1C71&PID_C131", # Brailliant BI 40X
"VID_1C71&PID_C141", # Brailliant BI 20X
"VID_1C71&PID_C00A", # BrailleNote Touch
"VID_1C71&PID_C00E", # BrailleNote Touch v2
},
)
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_1C71&PID_C005", # Brailliant BI 32, 40 and 80
"VID_1C71&PID_C021", # Brailliant BI 14
},
)
driverRegistrar.addBluetoothDevices(
lambda m: (
m.type == bdDetect.DeviceType.SERIAL
m.type == bdDetect.ProtocolType.SERIAL
and (
m.id.startswith("Brailliant B") or m.id == "Brailliant 80" or "BrailleNote Touch" in m.id
)
)
or (
m.type == bdDetect.DeviceType.HID
m.type == bdDetect.ProtocolType.HID
and m.deviceInfo.get("manufacturer") == "Humanware"
and m.deviceInfo.get("product")
in (
"Brailliant HID",
"APH Chameleon 20",
"APH Mantis Q40",
"Humanware BrailleOne",
"NLS eReader",
"NLS eReader Humanware",
"Brailliant BI 40X",
"Brailliant BI 20X",
and (
(
m.deviceInfo.get("product")
in (
"APH Chameleon 20",
"APH Mantis Q40",
"Brailliant BI 40X",
"Brailliant BI 20X",
)
and bdDetect._isHIDUsagePageMatch(m, HID_USAGE_PAGE)
)
or m.deviceInfo.get("product")
in (
"Brailliant HID",
"Humanware BrailleOne",
"NLS eReader",
"NLS eReader Humanware",
)
)
),
)
Expand All @@ -143,7 +158,7 @@ def __init__(self, port="auto"):
self.numCells = 0

for portType, portId, port, portInfo in self._getTryPorts(port):
self.isHid = portType == bdDetect.DeviceType.HID
self.isHid = portType == bdDetect.ProtocolType.HID
# Try talking to the display.
try:
if self.isHid:
Expand Down
8 changes: 4 additions & 4 deletions source/brailleDisplayDrivers/eurobraille/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_C251&PID_1122", # Esys (version < 3.0, no SD card
"VID_C251&PID_1123", # Esys (version >= 3.0, with HID keyboard, no SD card
Expand All @@ -67,7 +67,7 @@ def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
},
)
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_28AC&PID_0012", # b.note
"VID_28AC&PID_0013", # b.note 2
Expand Down Expand Up @@ -97,7 +97,7 @@ def __init__(self, port="Auto"):
for portType, portId, port, portInfo in self._getTryPorts(port):
# At this point, a port bound to this display has been found.
# Try talking to the display.
self.isHid = portType == bdDetect.DeviceType.HID
self.isHid = portType == bdDetect.ProtocolType.HID
try:
if self.isHid:
self._dev = hwIo.Hid(
Expand Down Expand Up @@ -173,7 +173,7 @@ def terminate(self):
def _prepFirstByteStreamAndData(
self,
data: bytes,
) -> (bytes, Union[BytesIO, hwIo.IoBase], bytes):
) -> tuple[bytes, Union[BytesIO, hwIo.IoBase], bytes]:
if self.isHid:
# data contains the entire packet.
# HID Packets start with 0x00.
Expand Down
4 changes: 2 additions & 2 deletions source/brailleDisplayDrivers/freedomScientific.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.CUSTOM,
bdDetect.ProtocolType.CUSTOM,
{
"VID_0F4E&PID_0100", # Focus 1
"VID_0F4E&PID_0111", # PAC Mate
Expand Down Expand Up @@ -243,7 +243,7 @@ def __init__(self, port="auto"):
self.gestureMap.add("br(freedomScientific):rightWizWheelDown", *action[2])
super(BrailleDisplayDriver, self).__init__()
for portType, portId, port, portInfo in self._getTryPorts(port):
self.isUsb = portType == bdDetect.DeviceType.CUSTOM
self.isUsb = portType == bdDetect.ProtocolType.CUSTOM
# Try talking to the display.
try:
if self.isUsb:
Expand Down
8 changes: 4 additions & 4 deletions source/brailleDisplayDrivers/handyTech.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver, ScriptableObject):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_0403&PID_6001", # FTDI chip
"VID_0921&PID_1200", # GoHubs chip
Expand All @@ -698,7 +698,7 @@ def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):

# Newer Handy Tech displays have a native HID processor
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_1FE4&PID_0054", # Active Braille
"VID_1FE4&PID_0055", # Connect Braille
Expand All @@ -723,7 +723,7 @@ def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):

# Some older HT displays use a HID converter and an internal serial interface
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.HID,
bdDetect.ProtocolType.HID,
{
"VID_1FE4&PID_0003", # USB-HID adapter
"VID_1FE4&PID_0074", # Braille Star 40
Expand Down Expand Up @@ -774,7 +774,7 @@ def __init__(self, port="auto"):
for portType, portId, port, portInfo in self._getTryPorts(port):
# At this point, a port bound to this display has been found.
# Try talking to the display.
self.isHid = portType == bdDetect.DeviceType.HID
self.isHid = portType == bdDetect.ProtocolType.HID
self.isHidSerial = portId in USB_IDS_HID_CONVERTER
self.port = port
try:
Expand Down
2 changes: 1 addition & 1 deletion source/brailleDisplayDrivers/hidBrailleStandard.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def __init__(self, port="auto"):
self.numCols = 0

for portType, portId, port, portInfo in self._getTryPorts(port):
if portType != bdDetect.DeviceType.HID:
if portType != bdDetect.ProtocolType.HID:
continue
# Try talking to the display.
try:
Expand Down
16 changes: 8 additions & 8 deletions source/brailleDisplayDrivers/hims.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,20 +281,20 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
deviceTypes = {
bdDetect.DeviceType.HID: (
bdDetect.ProtocolType.HID: (
{
"VID_045E&PID_940A", # Braille Edge3S 40
},
True,
),
bdDetect.DeviceType.CUSTOM: (
bdDetect.ProtocolType.CUSTOM: (
{
"VID_045E&PID_930A", # Braille Sense & Smart Beetle
"VID_045E&PID_930B", # Braille EDGE 40
},
False,
),
bdDetect.DeviceType.SERIAL: (
bdDetect.ProtocolType.SERIAL: (
{
"VID_0403&PID_6001",
"VID_1A86&PID_55D3", # Braille Edge2S 40
Expand Down Expand Up @@ -329,17 +329,17 @@ def __init__(self, port="auto"):

for match in self._getTryPorts(port):
portType, portId, port, portInfo = match
self.isBulk = portType == bdDetect.DeviceType.CUSTOM
self.isHID = portType == bdDetect.DeviceType.HID
self.isBulk = portType == bdDetect.ProtocolType.CUSTOM
self.isHID = portType == bdDetect.ProtocolType.HID
# Try talking to the display.
try:
match portType:
case bdDetect.DeviceType.HID:
case bdDetect.ProtocolType.HID:
self._dev = hwIo.Hid(port, onReceive=self._hidOnReceive)
case bdDetect.DeviceType.CUSTOM:
case bdDetect.ProtocolType.CUSTOM:
# onReceiveSize based on max packet size according to USB endpoint information.
self._dev = hwIo.Bulk(port, 0, 1, self._onReceive, onReceiveSize=64)
case bdDetect.DeviceType.SERIAL:
case bdDetect.ProtocolType.SERIAL:
self._dev = hwIo.Serial(
port,
baudrate=BAUD_RATE,
Expand Down
2 changes: 1 addition & 1 deletion source/brailleDisplayDrivers/nattiqbraille.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_2341&PID_8036", # Atmel-based USB Serial for Nattiq nBraille
},
Expand Down
8 changes: 4 additions & 4 deletions source/brailleDisplayDrivers/seikantk.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import serial

import braille
from bdDetect import DeviceType, DeviceMatch, DriverRegistrar
from bdDetect import DeviceMatch, DriverRegistrar
import brailleInput
import inputCore
import bdDetect
Expand Down Expand Up @@ -107,7 +107,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: DriverRegistrar):
driverRegistrar.addUsbDevices(
DeviceType.HID,
bdDetect.ProtocolType.HID,
{
vidpid, # Seika Notetaker
},
Expand All @@ -134,8 +134,8 @@ def __init__(self, port: typing.Union[None, str, DeviceMatch]):
log.debug(f"Seika Notetaker braille driver: ({port!r})")
dev: typing.Optional[typing.Union[hwIo.Hid, hwIo.Serial]] = None
for match in self._getTryPorts(port):
self.isHid = match.type == bdDetect.DeviceType.HID
self.isSerial = match.type == bdDetect.DeviceType.SERIAL
self.isHid = match.type == bdDetect.ProtocolType.HID
self.isSerial = match.type == bdDetect.ProtocolType.SERIAL
try:
if self.isHid:
log.info("Trying Seika notetaker on USB-HID")
Expand Down
2 changes: 1 addition & 1 deletion source/brailleDisplayDrivers/superBrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class BrailleDisplayDriver(braille.BrailleDisplayDriver):
@classmethod
def registerAutomaticDetection(cls, driverRegistrar: bdDetect.DriverRegistrar):
driverRegistrar.addUsbDevices(
bdDetect.DeviceType.SERIAL,
bdDetect.ProtocolType.SERIAL,
{
"VID_10C4&PID_EA60", # SuperBraille 3.2
},
Expand Down
Loading

0 comments on commit a7fa0d6

Please sign in to comment.