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

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 usb 

27 

28 

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

30 """Lists 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_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. 

81 

82Examples:[code] 

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

84 

85""" 

86 

87 

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

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 serial 

110 

111 

112def _list_serial_devices() -> None: 

113 """Lists the connected serial devices in table format.""" 

114 

115 devices = serial_util.scan_serial_devices() 

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

164 

165Examples:[code] 

166 apio devices 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="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.""" 

185 

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 ) 

193 

194 # -- List all connected serial devices 

195 _list_serial_devices() 

196 sys.exit(0) 

197 

198 

199# --- apio devices 

200 

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

207 

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] 

218 

219 

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

229 

230 # pass