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

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 

8 

9"""Implementation of 'apio devices' command""" 

10 

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 

24 

25 

26# --- apio devices scan-usb 

27 

28 

29def _list_usb_devices(apio_ctx: ApioContext) -> None: 

30 """Scans and display the connected USB devices in table format.""" 

31 

32 devices = usb_util.scan_usb_devices(apio_ctx=apio_ctx) 

33 

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 

38 

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 ) 

48 

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) 

56 

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) 

66 

67 # -- Add row. 

68 table.add_row(*values) 

69 

70 # -- Render the table. 

71 cout() 

72 ctable(table) 

73 cout(f"Found {util.plurality(devices, 'USB device')}", style=SUCCESS) 

74 

75 

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. 

81 

82Examples:[code] 

83 apio devices scan-usb # List the usb devices.[/code] 

84 

85""" 

86 

87 

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.""" 

96 

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 ) 

103 

104 # -- List all usb devices 

105 _list_usb_devices(apio_ctx) 

106 

107 

108# -- apio devices scan-serial 

109 

110 

111def _list_serial_devices(apio_ctx: ApioContext) -> None: 

112 """Scans and displays the connected serial devices in table format.""" 

113 

114 devices = serial_util.scan_serial_devices(apio_ctx) 

115 

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 

120 

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 ) 

130 

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) 

138 

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) 

148 

149 # -- Add row. 

150 table.add_row(*values) 

151 

152 # -- Render the table. 

153 cout() 

154 ctable(table) 

155 cout(f"Found {util.plurality(devices, 'device')}", style=SUCCESS) 

156 

157 

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. 

163 

164Examples:[code] 

165 apio devices scan-serial # List the serial devices.[/code] 

166 

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. 

169 

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""" 

174 

175 

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.""" 

184 

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 ) 

191 

192 # -- List all connected serial devices 

193 _list_serial_devices(apio_ctx) 

194 

195 

196# --- apio devices 

197 

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""" 

204 

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] 

215 

216 

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.""" 

226 

227 # pass