Skip to content

Commit 1ab4cf5

Browse files
authored
Add support for adding custom vendor IDs and product IDs (#12)
* Add support for adding custom vendor IDs and product IDs resolved all remaining issues for CI. Reformat type hints for linting Fix formatting Fixed mypy errors Resolved linting errors * Use vid and pid keyword arguments in Device's constructor
1 parent 192239d commit 1ab4cf5

File tree

6 files changed

+49
-40
lines changed

6 files changed

+49
-40
lines changed

docs/how_to.rst

+9-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ To see the vendor / product IDs which are supported, run the following::
2323
0x6001, 0x6010, 0x6011, 0x6014, 0x6015
2424

2525
If a FTDI device with a VID / PID not matching the above is required, then
26-
the device's values should be appended to the appropriate list after import::
26+
the device's vendor ID and product ID can be specified with `vid` or `pid`
27+
keyword arguments passed to Device constructors. For example, to open a device
28+
with VID 0x1234 and PID 0x5678, use::
29+
30+
>>> from pylibftdi import Device
31+
>>> dev = Device(vid=0x1234, pid=0x5678)
32+
33+
Alternatively, the device's vendor or product ID can be appended to the appropriate
34+
list after import::
2735

2836
>>> from pylibftdi import USB_PID_LIST, USB_VID_LIST, Device
2937
>>> USB_PID_LIST.append(0x1234)

src/pylibftdi/device.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ def __init__(
172172
Useful in the event that multiple devices of differing VID/PID
173173
are attached, where `device_index` is insufficient to select
174174
as device indexing restarts at 0 for each VID/PID combination.
175+
176+
:param vid: optional vendor ID to open. If omitted, the default USB_VID_LIST
177+
is used to search for devices.
178+
179+
:param pid: optional product ID to open. If omitted, the default USB_PID_LIST
180+
is used to search for devices.
175181
"""
176182
self._opened = False
177183

@@ -209,6 +215,8 @@ def __init__(
209215
# list_index (from parameter `index`) is an optional integer index
210216
# into list_devices() entries.
211217
self.list_index = kwargs.pop("index", None)
218+
self.vid = kwargs.pop("vid", None)
219+
self.pid = kwargs.pop("pid", None)
212220

213221
# lazy_open tells us not to open immediately.
214222
if not self.lazy_open:
@@ -321,7 +329,9 @@ def _open_device(self) -> int:
321329
"""
322330
# FTDI vendor/product ids required here.
323331
res: int = -1
324-
for usb_vid, usb_pid in itertools.product(USB_VID_LIST, USB_PID_LIST):
332+
vid_list = [self.vid] if self.vid is not None else USB_VID_LIST
333+
pid_list = [self.pid] if self.pid is not None else USB_PID_LIST
334+
for usb_vid, usb_pid in itertools.product(vid_list, pid_list):
325335
open_args = [byref(self.ctx), usb_vid, usb_pid, 0, 0, self.device_index]
326336
if self.device_id is None:
327337
res = self.fdll.ftdi_usb_open_desc_index(*tuple(open_args))
@@ -482,7 +492,7 @@ def flush(self, flush_what: int = FLUSH_BOTH) -> None:
482492
fn = self.fdll.ftdi_usb_purge_tx_buffer
483493
else:
484494
raise ValueError(
485-
"Invalid value passed to %s.flush()" % self.__class__.__name__
495+
f"Invalid value passed to {self.__class__.__name__}.flush()"
486496
)
487497
res = fn(byref(self.ctx))
488498
if res != 0:

src/pylibftdi/examples/bit_server.py

+28-34
Original file line numberDiff line numberDiff line change
@@ -27,45 +27,39 @@ class ThreadingServer(ThreadingMixIn, HTTPServer):
2727

2828
def get_page():
2929
port = switch.port
30-
page = (
31-
"""
32-
<!DOCTYPE html>
33-
<html>
34-
<head>
35-
<title>%s - pylibftdi</title>
36-
</head>
37-
<body>
38-
<div>
39-
"""
40-
% port
41-
)
30+
page = f"""
31+
<!DOCTYPE html>
32+
<html>
33+
<head>
34+
<title>{port} - pylibftdi</title>
35+
</head>
36+
<body>
37+
<div>
38+
"""
4239
for i in range(8):
4340
bit = 7 - i
4441
is_on = port & (1 << bit)
4542
color = "#00FF00" if is_on else "#FF0000"
46-
page += """
47-
<fieldset style="background-color: %s; display: inline-block; margin:0px; padding: 8px;">
48-
<form action="" method="post" >
49-
<input type="checkbox" onchange="document.querySelector('[name=bit%d]').value=this.checked; document.forms[%d].submit()" %s />
50-
<input type="hidden" name="bit%d" />
51-
</form>
52-
</fieldset>
53-
""" % ( # noqa: E501
54-
color,
55-
bit,
56-
i,
57-
'checked="checked"' if is_on else "",
58-
bit,
59-
)
60-
page += (
43+
page += f"""
44+
<fieldset style="background-color: {
45+
color
46+
}; display: inline-block; margin:0px; padding: 8px;">
47+
<form action="" method="post" >
48+
<input type="checkbox" onchange="document.querySelector('[name=bit{
49+
bit
50+
}]').value=this.checked; document.forms[{
51+
i
52+
}].submit()" {
53+
'checked="checked"' if is_on else ""
54+
} />
55+
<input type="hidden" name="bit{bit}" />
56+
</form>
57+
</fieldset>
58+
</div>
59+
DATA={port}
60+
</body>
61+
</html>
6162
"""
62-
</div>
63-
DATA=%s
64-
</body>
65-
</html>
66-
"""
67-
% port
68-
)
6963
return page
7064

7165

tests/test_bitbang.py

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
from pylibftdi import FtdiError
1717
from pylibftdi.bitbang import BitBangDevice
18-
1918
from tests.test_common import CallCheckMixin, LoopDevice
2019

2120

tests/test_device.py

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
from pylibftdi import FtdiError
1717
from pylibftdi.device import Device
18-
1918
from tests.test_common import CallCheckMixin, LoopDevice
2019

2120
# and now some test cases...

tests/test_serial.py

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import unittest
1515

1616
from pylibftdi.serial_device import SerialDevice
17-
1817
from tests.test_common import CallCheckMixin, LoopDevice
1918

2019

0 commit comments

Comments
 (0)