296a4b1f66
Updated - shebang removed in favor of the use of env (man env) more versatile and useful to portability
131 lines
4.2 KiB
Python
Executable file
131 lines
4.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# NOTE: prefer the use of [/usr/bin/env] and call the correct python interpreter python3
|
|
# instead of using the shebang. [env] will find the correct binary in your environement
|
|
# and brings other interesting features which are great to portability (man env).
|
|
|
|
import serial
|
|
import serial.tools.list_ports
|
|
import os.path
|
|
import argparse
|
|
from time import sleep
|
|
|
|
parser = argparse.ArgumentParser(description='Reset an Arduino')
|
|
parser.add_argument('--zero', action='store_true', help='Reset Arduino Zero or similar Native USB to enter bootloader')
|
|
parser.add_argument('--caterina', action='store_true', help='Reset a Leonardo, Micro, Robot or LilyPadUSB.')
|
|
parser.add_argument('--verbose', action='store_true', help="Watch what's going on on STDERR.")
|
|
parser.add_argument('--period', default=0.1, help='Specify the DTR pulse width in seconds.')
|
|
parser.add_argument('port', nargs=1, help='Serial device e.g. /dev/ttyACM0')
|
|
args = parser.parse_args()
|
|
|
|
|
|
def list_ports(output=False):
|
|
""" Lists serial ports attached
|
|
|
|
:returns
|
|
A list of paths to serial ports on system
|
|
"""
|
|
ports = serial.tools.list_ports.comports()
|
|
connected = [port[0] for port in ports]
|
|
if output:
|
|
print(connected)
|
|
|
|
return connected
|
|
|
|
|
|
def new_port(old, new):
|
|
""" Checks if a new port has attached
|
|
|
|
Args:
|
|
old: previous list of ports to check
|
|
new: current list of ports to check
|
|
Returns:
|
|
index of port in 'new' if new port found, otherwise -1
|
|
"""
|
|
new_port = -1
|
|
|
|
for port in new:
|
|
if port not in old:
|
|
new_port = new.index(port)
|
|
break
|
|
|
|
return new_port
|
|
|
|
|
|
if args.zero:
|
|
# number of trys to attempt
|
|
zero_attempts = 20 # ~2 seconds
|
|
initial_ports = list_ports(args.verbose)
|
|
|
|
if args.verbose:
|
|
print('Attempting to enter bootloader using 1200 bps open/close on port %s' % args.port[0])
|
|
|
|
ser = serial.Serial(args.port[0], 57600)
|
|
ser.close()
|
|
ser.baudrate = 1200
|
|
|
|
# do the open/close at 1200 BAUD
|
|
ser.open()
|
|
ser.close()
|
|
|
|
if args.verbose:
|
|
print('Done. Waiting for bootloader port to attach...')
|
|
|
|
# get new list of ports
|
|
reset_ports = list_ports(args.verbose)
|
|
|
|
# wait for new port or port to return
|
|
port_index = new_port(initial_ports, reset_ports)
|
|
|
|
# keep checking until new port appears or timeout
|
|
while port_index < 0:
|
|
# count down attempts and leave if expired
|
|
zero_attempts -= 1
|
|
if zero_attempts < 0:
|
|
break
|
|
sleep(0.1)
|
|
# get list of ports after bootloader toggle performed
|
|
reset_ports = list_ports(args.verbose)
|
|
# if a port drops, set initial ports to reset ports so that
|
|
# next attached device will be new port
|
|
if (len(reset_ports) < len(initial_ports)):
|
|
initial_ports = reset_ports
|
|
# check if a new port has attached and return the index if it has
|
|
port_index = new_port(initial_ports, reset_ports)
|
|
# return the new port if detected, otherwise return passed port
|
|
if port_index == -1:
|
|
bootloader_port = args.port[0]
|
|
else:
|
|
bootloader_port = reset_ports[port_index]
|
|
|
|
# print so that `tail -1` can be piped for bootloader port
|
|
print(bootloader_port)
|
|
elif args.caterina:
|
|
if args.verbose: print('Forcing reset using 1200bps open/close on port %s' % args.port[0])
|
|
ser = serial.Serial(args.port[0], 57600)
|
|
ser.close()
|
|
|
|
# NOTE: pyserial_version is not declared anywhere so I assumed you meant
|
|
pyserial_version = float(serial.VERSION)
|
|
if pyserial_version < 3:
|
|
ser.setBaudrate (1200)
|
|
else:
|
|
ser.baudrate = 1200
|
|
|
|
ser.open()
|
|
ser.setRTS(True) # RTS line needs to be held high and DTR low
|
|
ser.setDTR(False) # (see Arduino IDE source code)
|
|
ser.close()
|
|
sleep(1)
|
|
|
|
while not os.path.exists(args.port[0]):
|
|
if args.verbose: print('Waiting for %s to come back' % args.port[0])
|
|
sleep(1)
|
|
|
|
if args.verbose: print('%s has come back after reset' % args.port[0])
|
|
else:
|
|
if args.verbose: print('Setting DTR high on %s for %ss' % (args.port[0],args.period))
|
|
ser = serial.Serial(args.port[0], 115200)
|
|
ser.setDTR(False)
|
|
sleep(args.period)
|
|
ser.setDTR(True)
|
|
ser.close()
|