#!/usr/bin/python3 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() 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()