Skip to content

Commit ce59b1e

Browse files
committed
Handle serial port errors gracefully
Catch SerialException and print a proper error message to stderr.
1 parent 092eedc commit ce59b1e

File tree

2 files changed

+176
-155
lines changed

2 files changed

+176
-155
lines changed

programmer/tinyprog/__init__.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ def get_ports(device_id):
8484
return ports
8585

8686

87+
class PortError(Exception):
88+
pass
89+
8790
class SerialPort(object):
8891
def __init__(self, port_name):
8992
self.port_name = port_name
@@ -93,21 +96,35 @@ def __str__(self):
9396
return self.port_name
9497

9598
def __enter__(self):
96-
self.ser = serial.Serial(
97-
self.port_name, timeout=1.0, writeTimeout=1.0).__enter__()
99+
try:
100+
self.ser = serial.Serial(
101+
self.port_name, timeout=1.0, writeTimeout=1.0).__enter__()
102+
except serial.SerialException as e:
103+
raise PortError("Failed to open serial port:\n%s" % str(e))
98104

99105
def __exit__(self, exc_type, exc_val, exc_tb):
100-
self.ser.__exit__(exc_type, exc_val, exc_tb)
106+
try:
107+
self.ser.__exit__(exc_type, exc_val, exc_tb)
108+
except serial.SerialException as e:
109+
raise PortError("Failed to close serial port:\n%s" % str(e))
101110

102111
def write(self, data):
103-
self.ser.write(data)
112+
try:
113+
self.ser.write(data)
114+
except serial.SerialException as e:
115+
raise PortError("Failed to write to serial port:\n%s" % str(e))
104116

105117
def flush(self):
106-
self.ser.flush()
118+
try:
119+
self.ser.flush()
120+
except serial.SerialException as e:
121+
raise PortError("Failed to flush serial port:\n%s" % str(e))
107122

108123
def read(self, length):
109-
return self.ser.read(length)
110-
124+
try:
125+
return self.ser.read(length)
126+
except serial.SerialException as e:
127+
raise PortError("Failed to read from serial port:\n%s" % str(e))
111128

112129
class UsbPort(object):
113130
def __init__(self, device):

programmer/tinyprog/__main__.py

Lines changed: 152 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from six.moves import input
88

99
import tinyprog
10-
from tinyprog import TinyProg, get_ports
10+
from tinyprog import TinyProg, get_ports, PortError
1111

1212

1313
# adapted from http://code.activestate.com/recipes/577058/
@@ -292,180 +292,184 @@ def parse_int(str_value):
292292
tinyprog.use_libusb = args.libusb
293293
tinyprog.use_pyserial = args.pyserial
294294

295-
active_boards = get_ports(device) + get_ports("1209:2100")
295+
try:
296+
active_boards = get_ports(device) + get_ports("1209:2100")
296297

297-
if args.meta:
298-
meta = []
299-
for port in active_boards:
300-
with port:
301-
p = TinyProg(port)
302-
m = p.meta.root
303-
m["port"] = str(port)
304-
meta.append(m)
305-
print(json.dumps(meta, indent=2))
306-
sys.exit(0)
298+
if args.meta:
299+
meta = []
300+
for port in active_boards:
301+
with port:
302+
p = TinyProg(port)
303+
m = p.meta.root
304+
m["port"] = str(port)
305+
meta.append(m)
306+
print(json.dumps(meta, indent=2))
307+
sys.exit(0)
307308

308-
print("")
309-
print(" TinyProg CLI")
310-
print(" ------------")
309+
print("")
310+
print(" TinyProg CLI")
311+
print(" ------------")
311312

312-
print(" Using device id {}".format(device))
313+
print(" Using device id {}".format(device))
313314

314-
# find port to use
315-
active_port = None
316-
if args.com is not None:
317-
active_port = tinyprog.SerialPort(args.com)
315+
# find port to use
316+
active_port = None
317+
if args.com is not None:
318+
active_port = tinyprog.SerialPort(args.com)
318319

319-
elif args.id is not None:
320-
active_port = get_port_by_uuid(device, args.id)
320+
elif args.id is not None:
321+
active_port = get_port_by_uuid(device, args.id)
321322

322-
elif not active_boards:
323-
print("""\
323+
elif not active_boards:
324+
print("""\
324325
No port was specified and no active bootloaders found.
325326
Activate bootloader by pressing the reset button.
326327
""")
327-
sys.exit(1)
328+
sys.exit(1)
328329

329-
elif len(active_boards) == 1:
330-
print("""\
330+
elif len(active_boards) == 1:
331+
print("""\
331332
Only one board with active bootloader, using it.
332333
""")
333-
active_port = active_boards[0]
334+
active_port = active_boards[0]
334335

335-
else:
336-
print("""\
336+
else:
337+
print("""\
337338
Please choose a board with the -c or -i option. Using first board in list.
338339
""")
339-
active_port = active_boards[0]
340-
341-
# list boards
342-
if args.list or active_port is None:
343-
print(" Boards with active bootloaders:")
344-
for port in active_boards:
345-
with port:
346-
p = TinyProg(port)
347-
m = p.meta.root
348-
print_board(port, m)
349-
350-
if len(active_boards) == 0:
351-
print("""\
340+
active_port = active_boards[0]
341+
342+
# list boards
343+
if args.list or active_port is None:
344+
print(" Boards with active bootloaders:")
345+
for port in active_boards:
346+
with port:
347+
p = TinyProg(port)
348+
m = p.meta.root
349+
print_board(port, m)
350+
351+
if len(active_boards) == 0:
352+
print("""\
352353
No active bootloaders found. Check USB connections
353354
and press reset button to activate bootloader.""")
354355

355-
if args.update_bootloader:
356-
boards_needing_update = (
357-
check_for_wrong_tinyfpga_bx_vidpid() + check_for_new_bootloader())
356+
if args.update_bootloader:
357+
boards_needing_update = (
358+
check_for_wrong_tinyfpga_bx_vidpid() + check_for_new_bootloader())
358359

359-
if len(boards_needing_update) == 0:
360-
print("""\
360+
if len(boards_needing_update) == 0:
361+
print("""\
361362
All connected and active boards are up to date!""")
362-
else:
363-
for port in boards_needing_update:
364-
perform_bootloader_update(port)
365-
366-
# program the flash memory
367-
if (args.program is not None) or (args.program_userdata is not None) or (
368-
args.program_image is not None):
369-
boot_fpga = False
370-
371-
def progress(info):
372-
if isinstance(info, str):
373-
print(" " + str(info))
374-
375-
with active_port:
376-
fpga = TinyProg(active_port, progress)
377-
378-
if args.program is not None:
379-
print(" Programming %s with %s" % (
380-
active_port, args.program))
381-
382-
bitstream = fpga.slurp(args.program)
383-
384-
if args.addr is not None:
385-
addr = parse_int(args.addr)
386-
else:
387-
addr = fpga.meta.userimage_addr_range()[0]
388-
389-
if addr < 0:
390-
print(" Negative write addr: {}".format(addr))
391-
sys.exit(1)
392-
if not fpga.is_bootloader_active():
393-
print(" Bootloader not active")
394-
sys.exit(1)
395-
396-
if check_if_overwrite_bootloader(
397-
addr, len(bitstream),
398-
fpga.meta.userimage_addr_range()):
399-
boot_fpga = True
400-
print(" Programming at addr {:06x}".format(addr))
401-
if not fpga.program_bitstream(addr, bitstream):
363+
else:
364+
for port in boards_needing_update:
365+
perform_bootloader_update(port)
366+
367+
# program the flash memory
368+
if (args.program is not None) or (args.program_userdata is not None) or (
369+
args.program_image is not None):
370+
boot_fpga = False
371+
372+
def progress(info):
373+
if isinstance(info, str):
374+
print(" " + str(info))
375+
376+
with active_port:
377+
fpga = TinyProg(active_port, progress)
378+
379+
if args.program is not None:
380+
print(" Programming %s with %s" % (
381+
active_port, args.program))
382+
383+
bitstream = fpga.slurp(args.program)
384+
385+
if args.addr is not None:
386+
addr = parse_int(args.addr)
387+
else:
388+
addr = fpga.meta.userimage_addr_range()[0]
389+
390+
if addr < 0:
391+
print(" Negative write addr: {}".format(addr))
402392
sys.exit(1)
393+
if not fpga.is_bootloader_active():
394+
print(" Bootloader not active")
395+
sys.exit(1)
396+
397+
if check_if_overwrite_bootloader(
398+
addr, len(bitstream),
399+
fpga.meta.userimage_addr_range()):
400+
boot_fpga = True
401+
print(" Programming at addr {:06x}".format(addr))
402+
if not fpga.program_bitstream(addr, bitstream):
403+
sys.exit(1)
403404

404-
# program user flash area
405-
if args.program_userdata is not None:
406-
print(" Programming %s with %s" % (
407-
active_port, args.program_userdata))
408-
409-
bitstream = fpga.slurp(args.program_userdata)
410-
411-
if args.addr is not None:
412-
addr = parse_int(args.addr)
413-
else:
414-
addr = fpga.meta.userdata_addr_range()[0]
415-
416-
if addr < 0:
417-
print(" Negative write addr: {}".format(addr))
418-
sys.exit(1)
419-
if not fpga.is_bootloader_active():
420-
print(" Bootloader not active")
421-
sys.exit(1)
422-
423-
if check_if_overwrite_bootloader(
424-
addr, len(bitstream), fpga.meta.userdata_addr_range()):
425-
boot_fpga = True
426-
print(" Programming at addr {:06x}".format(addr))
427-
if not fpga.program_bitstream(addr, bitstream):
405+
# program user flash area
406+
if args.program_userdata is not None:
407+
print(" Programming %s with %s" % (
408+
active_port, args.program_userdata))
409+
410+
bitstream = fpga.slurp(args.program_userdata)
411+
412+
if args.addr is not None:
413+
addr = parse_int(args.addr)
414+
else:
415+
addr = fpga.meta.userdata_addr_range()[0]
416+
417+
if addr < 0:
418+
print(" Negative write addr: {}".format(addr))
428419
sys.exit(1)
420+
if not fpga.is_bootloader_active():
421+
print(" Bootloader not active")
422+
sys.exit(1)
423+
424+
if check_if_overwrite_bootloader(
425+
addr, len(bitstream), fpga.meta.userdata_addr_range()):
426+
boot_fpga = True
427+
print(" Programming at addr {:06x}".format(addr))
428+
if not fpga.program_bitstream(addr, bitstream):
429+
sys.exit(1)
429430

430-
# program user image and data area
431-
if args.program_image is not None:
432-
print(" Programming %s with %s" % (
433-
active_port, args.program_image))
434-
435-
bitstream = fpga.slurp(args.program_image)
436-
437-
if args.addr is not None:
438-
addr = parse_int(args.addr)
439-
else:
440-
addr = fpga.meta.userimage_addr_range()[0]
441-
442-
if addr < 0:
443-
print(" Negative write addr: {}".format(addr))
444-
sys.exit(1)
445-
if not fpga.is_bootloader_active():
446-
print(" Bootloader not active")
447-
sys.exit(1)
448-
449-
if check_if_overwrite_bootloader(
450-
addr, len(bitstream),
451-
(fpga.meta.userimage_addr_range()[0],
452-
fpga.meta.userdata_addr_range()[1])):
453-
boot_fpga = True
454-
print(" Programming at addr {:06x}".format(addr))
455-
if not fpga.program_bitstream(addr, bitstream):
431+
# program user image and data area
432+
if args.program_image is not None:
433+
print(" Programming %s with %s" % (
434+
active_port, args.program_image))
435+
436+
bitstream = fpga.slurp(args.program_image)
437+
438+
if args.addr is not None:
439+
addr = parse_int(args.addr)
440+
else:
441+
addr = fpga.meta.userimage_addr_range()[0]
442+
443+
if addr < 0:
444+
print(" Negative write addr: {}".format(addr))
445+
sys.exit(1)
446+
if not fpga.is_bootloader_active():
447+
print(" Bootloader not active")
456448
sys.exit(1)
457449

458-
if boot_fpga:
450+
if check_if_overwrite_bootloader(
451+
addr, len(bitstream),
452+
(fpga.meta.userimage_addr_range()[0],
453+
fpga.meta.userdata_addr_range()[1])):
454+
boot_fpga = True
455+
print(" Programming at addr {:06x}".format(addr))
456+
if not fpga.program_bitstream(addr, bitstream):
457+
sys.exit(1)
458+
459+
if boot_fpga:
460+
fpga.boot()
461+
print("")
462+
sys.exit(0)
463+
464+
# boot the FPGA
465+
if args.boot:
466+
print(" Booting " + str(active_port))
467+
with active_port:
468+
fpga = TinyProg(active_port)
459469
fpga.boot()
460-
print("")
461-
sys.exit(0)
462-
463-
# boot the FPGA
464-
if args.boot:
465-
print(" Booting " + str(active_port))
466-
with active_port:
467-
fpga = TinyProg(active_port)
468-
fpga.boot()
470+
except PortError as e:
471+
print(str(e), file=sys.stderr)
472+
sys.exit(1)
469473

470474
print("")
471475

0 commit comments

Comments
 (0)