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