aboutsummaryrefslogtreecommitdiff
path: root/bin/ard-reset-arduino
blob: d6f974f541e36c175e2dd9f5fb43bc03a426d474 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python

from __future__ import print_function
import serial
import serial.tools.list_ports
import os.path
import argparse
from time import sleep

pyserial_version = None
try:
  pyserial_version = int(serial.VERSION[0])
except:
  pyserial_version = 2  # less than 2.3

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()

    if pyserial_version < 3:
        ser.setBaudrate(1200)
    else:
        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 is -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()