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

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

23 

24 

25# --- apio devices scan-usb 

26 

27 

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

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

30 

31 devices = usb_util.scan_usb_devices(apio_ctx=apio_ctx) 

32 

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 

37 

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 ) 

47 

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) 

55 

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) 

65 

66 # -- Add row. 

67 table.add_row(*values) 

68 

69 # -- Render the table. 

70 cout() 

71 ctable(table) 

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

73 

74 

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. 

80 

81Examples:[code] 

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

83 

84""" 

85 

86 

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

95 

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 ) 

102 

103 # -- List all usb devices 

104 _list_usb_devices(apio_ctx) 

105 

106 

107# -- apio devices scan-serial 

108 

109 

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

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

112 

113 devices = serial_util.scan_serial_devices(apio_ctx) 

114 

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 

119 

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 ) 

129 

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) 

137 

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) 

147 

148 # -- Add row. 

149 table.add_row(*values) 

150 

151 # -- Render the table. 

152 cout() 

153 ctable(table) 

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

155 

156 

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. 

162 

163Examples:[code] 

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

165 

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. 

168 

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

173 

174 

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

183 

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 ) 

190 

191 # -- List all connected serial devices 

192 _list_serial_devices(apio_ctx) 

193 

194 

195# --- apio devices 

196 

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

203 

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] 

214 

215 

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

225 

226 # pass