Coverage for apio/commands/apio_devices.py: 44%
70 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-07 05:08 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-07 05:08 +0000
1# This file is part of the Apio project
2# (C) 2016-present FPGAwars
3# Project authors:
4# * Jesús Arroyo (Jesus89) (2016-2019)
5# * Juan Gonzalez (obijuan) (2019-2024)
6# * The Apio Team (2024-present)
7# License: GPLv2
9"""Implementation of 'apio devices' command"""
11import click
12from rich.table import Table
13from rich import box
14from apio.apio_context import (
15 ApioContext,
16 PackagesPolicy,
17 ProjectPolicy,
18 RemoteConfigPolicy,
19)
20from apio.utils.cmd_util import ApioGroup, ApioSubgroup, ApioCommand
21from apio.common.apio_console import cout, ctable
22from apio.common.apio_styles import BORDER, SUCCESS, ERROR, EMPH3
23from apio.utils import serial_util, usb_util, util
26# --- apio devices scan-usb
29def _list_usb_devices(apio_ctx: ApioContext) -> None:
30 """Scans and display the connected USB devices in table format."""
32 devices = usb_util.scan_usb_devices(apio_ctx=apio_ctx)
34 # -- If not found, print a message and exit.
35 if not devices: 35 ↛ 40line 35 didn't jump to line 40 because the condition on line 35 was always true
36 cout("No USB devices found.", style=ERROR)
37 return
39 # -- Define the table.
40 table = Table(
41 show_header=True,
42 show_lines=True,
43 box=box.SQUARE,
44 border_style=BORDER,
45 title="USB Devices",
46 title_justify="left",
47 )
49 # -- Add columns
50 table.add_column("VID:PID", no_wrap=True)
51 table.add_column("BUS:DEV", no_wrap=True, justify="center")
52 table.add_column("MANUFACTURER", no_wrap=True, style=EMPH3)
53 table.add_column("PRODUCT", no_wrap=True, style=EMPH3)
54 table.add_column("SERIAL-NUM", no_wrap=True)
55 table.add_column("TYPE", no_wrap=True)
57 # -- Add a raw per device
58 for device in devices:
59 values = []
60 values.append(f"{device.vid}:{device.pid}")
61 values.append(f"{device.bus}:{device.device}")
62 values.append(device.manufacturer)
63 values.append(device.product)
64 values.append(device.serial_number)
65 values.append(device.device_type)
67 # -- Add row.
68 table.add_row(*values)
70 # -- Render the table.
71 cout()
72 ctable(table)
73 cout(f"Found {util.plurality(devices, 'USB device')}", style=SUCCESS)
76# -- Text in the rich-text format of the python rich library.
77APIO_DEVICES_SCAN_USB_HELP = """
78The command 'apio devices scan-usb' scans and display the USB devices \
79currently connected to your computer. It is useful for diagnosing FPGA board \
80connectivity issues.
82Examples:[code]
83 apio devices scan-usb # List the usb devices.[/code]
85"""
88@click.command(
89 name="scan-usb",
90 cls=ApioCommand,
91 short_help="Scan for USB devices.",
92 help=APIO_DEVICES_SCAN_USB_HELP,
93)
94def _scan_usb_cli():
95 """Implements the 'apio devices scan-usb' command."""
97 # Create the apio context.
98 apio_ctx = ApioContext(
99 project_policy=ProjectPolicy.NO_PROJECT,
100 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
101 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
102 )
104 # -- List all usb devices
105 _list_usb_devices(apio_ctx)
108# -- apio devices scan-serial
111def _list_serial_devices(apio_ctx: ApioContext) -> None:
112 """Scans and displays the connected serial devices in table format."""
114 devices = serial_util.scan_serial_devices(apio_ctx)
116 # -- If not found, print a message and exit.
117 if not devices: 117 ↛ 122line 117 didn't jump to line 122 because the condition on line 117 was always true
118 cout("No SERIAL devices found.", style=ERROR)
119 return
121 # -- Define the table.
122 table = Table(
123 show_header=True,
124 show_lines=True,
125 box=box.SQUARE,
126 border_style=BORDER,
127 title="SERIAL Ports",
128 title_justify="left",
129 )
131 # -- Add columns
132 table.add_column("PORT", no_wrap=True, style=EMPH3)
133 table.add_column("VID:PID", no_wrap=True)
134 table.add_column("MANUFACTURER", no_wrap=True, style=EMPH3)
135 table.add_column("PRODUCT", no_wrap=True, style=EMPH3)
136 table.add_column("SERIAL-NUM", no_wrap=True)
137 table.add_column("TYPE", no_wrap=True)
139 # -- Add a raw per device
140 for device in devices:
141 values = []
142 values.append(device.port)
143 values.append(f"{device.vid}:{device.pid}")
144 values.append(device.manufacturer)
145 values.append(device.product)
146 values.append(device.serial_number)
147 values.append(device.device_type)
149 # -- Add row.
150 table.add_row(*values)
152 # -- Render the table.
153 cout()
154 ctable(table)
155 cout(f"Found {util.plurality(devices, 'device')}", style=SUCCESS)
158# -- Text in the rich-text format of the python rich library.
159APIO_DEVICES_SCAN_SERIAL_HELP = """
160The command 'apio devices scan-serial' scans and displays the serial devices\
161currently connected to your computer. It is useful for diagnosing FPGA board \
162connectivity issues.
164Examples:[code]
165 apio devices scan-serial # List the serial devices.[/code]
167Note that devices such as FTDI FTDI2232 that have more than one channel \
168are listed as multiple rows, one for each of their serial ports.
170On Windows, manufacturer and product strings of FTDI based devices \
171may show their FTDI generic values rather than the custom values such \
172such as 'Alhambra II' set by the device manufacturer.
173"""
176@click.command(
177 name="scan-serial",
178 cls=ApioCommand,
179 short_help="Scan for serial devices.",
180 help=APIO_DEVICES_SCAN_SERIAL_HELP,
181)
182def _scan_serial_cli():
183 """Implements the 'apio devices scan-serial' command."""
185 # -- Create the apio context.
186 apio_ctx = ApioContext(
187 project_policy=ProjectPolicy.NO_PROJECT,
188 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
189 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
190 )
192 # -- List all connected serial devices
193 _list_serial_devices(apio_ctx)
196# --- apio devices
198# -- Text in the rich-text format of the python rich library.
199APIO_DEVICES_HELP = """
200The command group 'apio devices' includes subcommands that lists devices \
201that are attached to the computer. It's main usage is diagnostics or \
202devices connectivity and drivers.
203"""
205# -- We have only a single group with the title 'Subcommands'.
206SUBGROUPS = [
207 ApioSubgroup(
208 "Subcommands",
209 [
210 _scan_usb_cli,
211 _scan_serial_cli,
212 ],
213 )
214]
217@click.command(
218 name="devices",
219 cls=ApioGroup,
220 subgroups=SUBGROUPS,
221 short_help="Scan attached devices.",
222 help=APIO_DEVICES_HELP,
223)
224def cli():
225 """Implements the 'apio devices' command."""
227 # pass