25
25
from pygdbmi .gdbcontroller import GdbController
26
26
27
27
TIMEOUT = 100 # seconds
28
+ DEFAULT_VERSION = Version ('1.10.2' )
28
29
29
30
30
31
# find a suitable gdb executable, falling back to defaults if needed
@@ -35,18 +36,30 @@ def find_suitable_gdb(gdb_path):
35
36
for p in ['arm-none-eabi-gdb' , 'gdb-multiarch' ]:
36
37
p = shutil .which (p )
37
38
if p :
38
- print ("GDB EXECUTABLE NOT FOUND! FALLING BACK TO %s" % p , file = sys .stderr )
39
+ print (f "GDB EXECUTABLE NOT FOUND! FALLING BACK TO { p } " , file = sys .stderr )
39
40
return p
40
41
print ("CANNOT LOCATE SUITABLE GDB EXECUTABLE!" , file = sys .stderr )
41
42
sys .exit (- 1 )
42
43
43
44
45
+ # detect the firmware version by parsing the product description for something like v1.10.2
46
+ def detect_firmware_version (port ):
47
+ matches = re .search (r"v[0-9]+.[0-9]+.[0-9]+" , port .product )
48
+
49
+ if not matches :
50
+ return None
51
+
52
+ return Version (matches .group (0 )[1 :])
53
+
54
+
44
55
# find all connected BMPs and store both GDB and UART interfaces
45
56
def detect_probes ():
46
57
gdb_ports = []
47
58
uart_ports = []
48
59
for p in serial .tools .list_ports .comports ():
49
60
if p .vid == 0x1D50 and p .pid in {0x6018 , 0x6017 }:
61
+ p .firmware_version = detect_firmware_version (p )
62
+
50
63
if re .fullmatch (r'COM\d\d' , p .device ):
51
64
p .device = '//./' + p .device
52
65
if 'GDB' in str (p .interface ) \
@@ -62,9 +75,11 @@ def detect_probes():
62
75
def enumerate_probes (ports ):
63
76
print ("found following Black Magic GDB servers:" )
64
77
for i , s in enumerate (ports ):
65
- print ("\t [%s]" % s .device , end = ' ' )
78
+ print (f "\t [{ s .device } ]" , end = ' ' )
66
79
if len (s .serial_number ) > 1 :
67
- print ("Serial:" , s .serial_number , end = ' ' )
80
+ print (f"Serial: { s .serial_number } " , end = ' ' )
81
+ if s .firmware_version :
82
+ print (f"Firmware: { s .firmware_version } " , end = ' ' )
68
83
if i == 0 :
69
84
print ("<- default" , end = ' ' )
70
85
print ('' )
@@ -74,7 +89,14 @@ def enumerate_probes(ports):
74
89
def search_serial (snr , ports ):
75
90
for port in ports :
76
91
if snr in port .serial_number :
77
- return port .device
92
+ return port
93
+
94
+
95
+ # search device with specific port number <prt> in a list of ports <ports>
96
+ def search_port (prt , ports ):
97
+ for port in ports :
98
+ if prt == port .device :
99
+ return port
78
100
79
101
80
102
# parse GDB output for targets
@@ -83,9 +105,11 @@ def detect_targets(gdbmi, res):
83
105
while True :
84
106
for msg in res :
85
107
if msg ['type' ] == 'target' :
86
- m = re .fullmatch (pattern = r"\s* (\d+)\s*(.*)\s*" , string = msg ['payload' ])
108
+ m = re .fullmatch (pattern = r"([\s\*]*) (\d+)\s*(.*)\s*" , string = msg ['payload' ])
87
109
if m :
88
- targets .append (m .group (2 ))
110
+ supported = "***" not in m .group (1 )
111
+ description = m .group (3 )
112
+ targets .append ((supported , description ))
89
113
elif msg ['type' ] == 'result' :
90
114
assert msg ['message' ] == 'done' , str (msg )
91
115
return targets
@@ -131,7 +155,7 @@ def download_to_flash(gdbmi):
131
155
while True :
132
156
for msg in res :
133
157
if msg ['type' ] == 'result' :
134
- assert msg ['message' ] == 'done' , "download failed: %s" % str ( msg )
158
+ assert msg ['message' ] == 'done' , f "download failed: { msg } "
135
159
if pbar .start_time :
136
160
pbar .finish ()
137
161
print ("downloading finished" )
@@ -141,14 +165,12 @@ def download_to_flash(gdbmi):
141
165
if section_name :
142
166
if first :
143
167
first = False
144
- print ("downloading... total size: %s"
145
- % humanize .naturalsize (total_size , gnu = True ))
168
+ print (f"downloading... total size: { humanize .naturalsize (total_size , gnu = True )} " )
146
169
if section_name != current_sec :
147
170
if pbar .start_time :
148
171
pbar .finish ()
149
172
current_sec = section_name
150
- print ("downloading section [%s] (%s)" % (
151
- section_name , humanize .naturalsize (section_size , gnu = True )))
173
+ print (f"downloading section [{ section_name } ] ({ humanize .naturalsize (section_size , gnu = True )} )" )
152
174
pbar = ProgressBar (widgets = [Percentage (), Bar ()], maxval = section_size ).start ()
153
175
if section_sent :
154
176
pbar .update (section_sent )
@@ -160,29 +182,50 @@ def check_flash(gdbmi):
160
182
while True :
161
183
for msg in res :
162
184
if msg ['type' ] == 'result' :
163
- assert msg ['message' ] == 'done' , "checking failed: %s" % str ( msg )
185
+ assert msg ['message' ] == 'done' , f "checking failed: { msg } "
164
186
print ("checking successful" )
165
187
return
166
188
elif msg ['type' ] == 'console' :
167
189
assert 'matched' in msg ['payload' ] and 'MIS-MATCHED' not in msg ['payload' ], \
168
- "checking failed: %s" % str ( msg )
190
+ f "checking failed: { msg } "
169
191
res = gdbmi .get_gdb_response (timeout_sec = TIMEOUT )
170
192
171
193
172
- # choose GDB or UART port, based on available ports and application arguments
173
- def choose_port (args , ports ):
174
- if args .port :
175
- port = args .port
194
+ # choose GDB or UART port, based on available ports and application arguments.
195
+ def choose_probe (args , ports ):
196
+ if args .serial :
197
+ descriptor = search_serial (args .serial , ports )
198
+ assert descriptor , "no BMP with this serial found"
199
+ elif args .port :
200
+ descriptor = search_port (args .port , ports )
201
+
202
+ # bail out if no descriptor found, because port could be a network address, a pipe or
203
+ # something else.
204
+ if not descriptor :
205
+ return (args .port , None )
176
206
else :
177
- enumerate_probes (ports )
178
- if args .serial :
179
- port = search_serial (args .serial , ports )
180
- assert port , "no BMP with this serial found"
207
+ assert len (ports ) > 0 , "no ports found"
208
+ descriptor = ports [0 ]
209
+
210
+ enumerate_probes (ports )
211
+ print (f'connecting to [{ descriptor .device } ]...' )
212
+ return (descriptor .device , descriptor )
213
+
214
+
215
+ # choose firmware version, based on available descriptors and application arguments.
216
+ def choose_firmware_version (args , descriptor ):
217
+ if args .bmp_version == "auto" :
218
+ if descriptor and descriptor .firmware_version :
219
+ version = descriptor .firmware_version
220
+ print (f"auto-detected firmware version { version } " )
181
221
else :
182
- assert len (ports ) > 0 , "no ports found"
183
- port = ports [0 ].device
184
- print ('connecting to [%s]...' % port )
185
- return port
222
+ version = DEFAULT_VERSION
223
+ print (f"unable to detect firmware version, assuming { version } or later" )
224
+ else :
225
+ version = Version (args .bmp_version )
226
+ print (f"using firmware version { version } " )
227
+
228
+ return version
186
229
187
230
188
231
# terminal mode, opens TTY program
@@ -193,7 +236,7 @@ def term_mode(args, uart_port):
193
236
194
237
# debug mode, opens GDB shell with options
195
238
def debug_mode (args , port ):
196
- gdb_args = ['-ex \' target extended-remote %s \' ' % port ]
239
+ gdb_args = [f '-ex \' target extended-remote { port } \' ' ]
197
240
if args .tpwr :
198
241
gdb_args .append ('-ex \' monitor tpwr enable\' ' )
199
242
if args .connect_srst :
@@ -208,8 +251,8 @@ def debug_mode(args, port):
208
251
gdb_args .append ('-ex \' monitor swd_scan\' ' )
209
252
else :
210
253
gdb_args .append ('-ex \' monitor swdp_scan\' ' )
211
- gdb_args .append ('-ex \' attach %s \' ' % args .attach )
212
- os .system (" " .join (['\" ' + args .gdb_path + ' \" ' ] + gdb_args + [args .file ]))
254
+ gdb_args .append (f '-ex \' attach { args .attach } \' ' )
255
+ os .system (" " .join ([f '\" { args .gdb_path } \" ' ] + gdb_args + [args .file ]))
213
256
214
257
215
258
def connect_to_target (args , port ):
@@ -220,7 +263,7 @@ def connect_to_target(args, port):
220
263
except TypeError :
221
264
# and then new API
222
265
gdbmi = GdbController (command = [args .gdb_path , "--nx" , "--quiet" , "--interpreter=mi2" , args .file ])
223
- assert gdb_write_and_wait_for_result (gdbmi , '-target-select extended-remote %s' % port , 'connecting' ,
266
+ assert gdb_write_and_wait_for_result (gdbmi , f '-target-select extended-remote { port } ' , 'connecting' ,
224
267
expected_result = 'connected' )
225
268
# set options
226
269
if args .connect_srst :
@@ -243,10 +286,13 @@ def connect_to_target(args, port):
243
286
targets = detect_targets (gdbmi , res )
244
287
assert len (targets ) > 0 , "no targets found"
245
288
print ("found following targets:" )
246
- for t in targets :
247
- print ("\t %s" % t )
289
+ for s , t in targets :
290
+ if not s :
291
+ print (f"\t { t } (unsupported)" )
292
+ else :
293
+ print (f"\t { t } " )
248
294
print ("" )
249
- return gdbmi
295
+ return ( gdbmi , targets )
250
296
251
297
252
298
def parse_args ():
@@ -258,9 +304,9 @@ def parse_args():
258
304
parser .add_argument ('--tpwr' , action = 'store_true' , help = 'enable target power' )
259
305
parser .add_argument ('--serial' , help = 'choose specific probe by serial number' )
260
306
parser .add_argument ('--port' , help = 'choose specific probe by port (overrides auto selection)' )
261
- parser .add_argument ('--attach' , help = 'choose specific target by number' , default = '1' )
307
+ parser .add_argument ('--attach' , help = 'choose specific target by number' , type = int , default = 1 )
262
308
parser .add_argument ('--gdb-path' , help = 'path to GDB' , default = 'gdb-multiarch' )
263
- parser .add_argument ('--bmp-version' , help = 'choose specific firmware version' , default = '1.10.0 ' )
309
+ parser .add_argument ('--bmp-version' , help = 'choose specific firmware version' , default = 'auto ' )
264
310
parser .add_argument ('--term-cmd' , help = 'serial terminal command' ,
265
311
default = 'picocom --nolock --imap lfcrlf --baud 115200 %s' )
266
312
@@ -279,26 +325,29 @@ def main():
279
325
g , u = detect_probes ()
280
326
281
327
if args .action == 'term' :
282
- port = choose_port (args , u )
328
+ ( port , _ ) = choose_probe (args , u )
283
329
284
330
term_mode (args , port )
285
331
else :
286
- port = choose_port (args , g )
332
+ ( port , descriptor ) = choose_probe (args , g )
287
333
288
334
args .file = args .file if args .file else ''
289
- args .bmp_version = Version (args . bmp_version )
335
+ args .bmp_version = choose_firmware_version (args , descriptor )
290
336
args .gdb_path = find_suitable_gdb (args .gdb_path )
291
337
292
338
if args .action == 'debug' :
293
339
debug_mode (args , port )
294
340
sys .exit (0 )
295
341
296
- gdbmi = connect_to_target (args , port )
342
+ ( gdbmi , targets ) = connect_to_target (args , port )
297
343
298
344
if args .action == 'list' :
299
345
sys .exit (0 )
300
346
301
- assert gdb_write_and_wait_for_result (gdbmi , '-target-attach %s' % args .attach , 'attaching to target' )
347
+ assert len (targets ) >= args .attach , "attach greater than number of targets"
348
+ assert targets [args .attach - 1 ][0 ], "target unsupported by probe"
349
+
350
+ assert gdb_write_and_wait_for_result (gdbmi , f'-target-attach { args .attach } ' , 'attaching to target' )
302
351
303
352
# reset mode: reset device using reset pin
304
353
if args .action == 'reset' :
0 commit comments