Coverage for apio / commands / apio_devices.py: 46%

73 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-10 03:35 +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""" 

9 

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 

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

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 sys.exit(0) 

107 

108 

109# -- apio devices scan-serial 

110 

111 

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

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

114 

115 devices = serial_util.scan_serial_devices(apio_ctx) 

116 

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 

121 

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 ) 

131 

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) 

139 

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) 

149 

150 # -- Add row. 

151 table.add_row(*values) 

152 

153 # -- Render the table. 

154 cout() 

155 ctable(table) 

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

157 

158 

159# -- Text in the rich-text format of the python rich library. 

160APIO_DEVICES_SCAN_SERIAL_HELP = """ 

161The command 'apio devices scan-serial' scans and displays the serial devices\ 

162currently connected to your computer. It is useful for diagnosing FPGA board \ 

163connectivity issues. 

164 

165Examples:[code] 

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

167 

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. 

170 

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

175 

176 

177@click.command( 

178 name="scan-serial", 

179 cls=ApioCommand, 

180 short_help="Scan for serial devices.", 

181 help=APIO_DEVICES_SCAN_SERIAL_HELP, 

182) 

183def _scan_serial_cli(): 

184 """Implements the 'apio devices scan-serial' command.""" 

185 

186 # -- Create the apio context. 

187 apio_ctx = ApioContext( 

188 project_policy=ProjectPolicy.NO_PROJECT, 

189 remote_config_policy=RemoteConfigPolicy.CACHED_OK, 

190 packages_policy=PackagesPolicy.ENSURE_PACKAGES, 

191 ) 

192 

193 # -- List all connected serial devices 

194 _list_serial_devices(apio_ctx) 

195 sys.exit(0) 

196 

197 

198# --- apio devices 

199 

200# -- Text in the rich-text format of the python rich library. 

201APIO_DEVICES_HELP = """ 

202The command group 'apio devices' includes subcommands that lists devices \ 

203that are attached to the computer. It's main usage is diagnostics or \ 

204devices connectivity and drivers. 

205""" 

206 

207# -- We have only a single group with the title 'Subcommands'. 

208SUBGROUPS = [ 

209 ApioSubgroup( 

210 "Subcommands", 

211 [ 

212 _scan_usb_cli, 

213 _scan_serial_cli, 

214 ], 

215 ) 

216] 

217 

218 

219@click.command( 

220 name="devices", 

221 cls=ApioGroup, 

222 subgroups=SUBGROUPS, 

223 short_help="Scan attached devices.", 

224 help=APIO_DEVICES_HELP, 

225) 

226def cli(): 

227 """Implements the 'apio devices' command.""" 

228 

229 # pass