Coverage for apio/commands/apio_devices.py: 46%
73 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-06 10:20 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-06 10:20 +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 sys
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 usb
29def _list_usb_devices(apio_ctx: ApioContext) -> None:
30 """Lists 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.vendor_id}:{device.product_id}")
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_USB_HELP = """
78The command 'apio devices usb' displays the USB devices currently \
79connected to your computer. It is useful for diagnosing FPGA board \
80connectivity issues.
82Examples:[code]
83 apio devices usb # List the usb devices.[/code]
85"""
88@click.command(
89 name="usb",
90 cls=ApioCommand,
91 short_help="List USB devices.",
92 help=APIO_DEVICES_USB_HELP,
93)
94def _usb_cli():
95 """Implements the 'apio devices 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)
106 sys.exit(0)
109# -- apio devices serial
112def _list_serial_devices() -> None:
113 """Lists the connected serial devices in table format."""
115 devices = serial_util.scan_serial_devices()
117 # -- If not found, print a message and exit.
118 if not devices: 118 ↛ 123line 118 didn't jump to line 123 because the condition on line 118 was always true
119 cout("No SERIAL devices found.", style=ERROR)
120 return
122 # -- Define the table.
123 table = Table(
124 show_header=True,
125 show_lines=True,
126 box=box.SQUARE,
127 border_style=BORDER,
128 title="SERIAL Ports",
129 title_justify="left",
130 )
132 # -- Add columns
133 table.add_column("PORT", no_wrap=True, style=EMPH3)
134 table.add_column("VID:PID", no_wrap=True)
135 table.add_column("MANUFACTURER", no_wrap=True, style=EMPH3)
136 table.add_column("PRODUCT", no_wrap=True, style=EMPH3)
137 table.add_column("SERIAL-NUM", no_wrap=True)
138 table.add_column("TYPE", no_wrap=True)
140 # -- Add a raw per device
141 for device in devices:
142 values = []
143 values.append(device.port)
144 values.append(f"{device.vendor_id}:{device.product_id}")
145 values.append(device.manufacturer)
146 values.append(device.product)
147 values.append(device.serial_number)
148 values.append(device.device_type)
150 # -- Add row.
151 table.add_row(*values)
153 # -- Render the table.
154 cout()
155 ctable(table)
156 cout(f"Found {util.plurality(devices, 'device')}", style=SUCCESS)
159# -- Text in the rich-text format of the python rich library.
160APIO_DEVICES_SERIAL_HELP = """
161The command 'apio devices serial' displays the serial devices currently \
162connected to your computer. It is useful for diagnosing FPGA board \
163connectivity issues.
165Examples:[code]
166 apio devices serial # List the serial devices.[/code]
168Note that devices such as FTDI FTDI2232 that have more than one channel \
169are listed as multiple rows, one for each of their serial ports.
171On Windows, manufacturer and product strings of FTDI based devices \
172may show their FTDI generic values rather than the custom values such \
173such as 'Alhambra II' set by the device manufacturer.
174"""
177@click.command(
178 name="serial",
179 cls=ApioCommand,
180 short_help="List serial devices.",
181 help=APIO_DEVICES_SERIAL_HELP,
182)
183def _serial_cli():
184 """Implements the 'apio devices serial' command."""
186 # -- Create the apio context. We create it for consistency though
187 # -- we don't use .t
188 _ = ApioContext(
189 project_policy=ProjectPolicy.NO_PROJECT,
190 remote_config_policy=RemoteConfigPolicy.CACHED_OK,
191 packages_policy=PackagesPolicy.ENSURE_PACKAGES,
192 )
194 # -- List all connected serial devices
195 _list_serial_devices()
196 sys.exit(0)
199# --- apio devices
201# -- Text in the rich-text format of the python rich library.
202APIO_DEVICES_HELP = """
203The command group 'apio devices' includes subcommands that lists devices
204that are attached to the computer. It's main usage is diagnostics or
205devices connectivity and drivers.
206"""
208# -- We have only a single group with the title 'Subcommands'.
209SUBGROUPS = [
210 ApioSubgroup(
211 "Subcommands",
212 [
213 _usb_cli,
214 _serial_cli,
215 ],
216 )
217]
220@click.command(
221 name="devices",
222 cls=ApioGroup,
223 subgroups=SUBGROUPS,
224 short_help="List attached devices.",
225 help=APIO_DEVICES_HELP,
226)
227def cli():
228 """Implements the 'apio devices' command."""
230 # pass