28
28
29
29
package processing .app .debug ;
30
30
31
+ import java .util .ArrayList ;
32
+ import java .util .List ;
33
+
31
34
import processing .app .Base ;
32
35
import processing .app .Preferences ;
36
+ import processing .app .Serial ;
33
37
import processing .app .SerialException ;
34
38
import processing .app .helpers .PreferencesMap ;
35
39
import processing .app .helpers .StringReplacer ;
36
40
41
+ import static processing .app .I18n ._ ;
42
+
37
43
public class BasicUploader extends Uploader {
38
44
39
45
public boolean uploadUsingPreferences (String buildPath , String className ,
@@ -50,14 +56,101 @@ public boolean uploadUsingPreferences(String buildPath, String className,
50
56
if (usingProgrammer || prefs .get ("upload.protocol" ) == null ) {
51
57
return uploadUsingProgrammer (buildPath , className );
52
58
}
59
+
60
+ // need to do a little dance for Leonardo and derivatives:
61
+ // open then close the port at the magic baudrate (usually 1200 bps) first
62
+ // to signal to the sketch that it should reset into bootloader. after doing
63
+ // this wait a moment for the bootloader to enumerate. On Windows, also must
64
+ // deal with the fact that the COM port number changes from bootloader to
65
+ // sketch.
66
+ String use1200bpsTouch = prefs .get ("upload.use_1200bps_touch" );
67
+ boolean doTouch = use1200bpsTouch != null && use1200bpsTouch .equals ("true" );
68
+ if (doTouch ) {
69
+ String uploadPort = prefs .get ("serial.port" );
70
+ String caterinaUploadPort = null ;
71
+ try {
72
+ // Toggle 1200 bps on selected serial port to force board reset.
73
+ List <String > before = Serial .list ();
74
+ if (before .contains (uploadPort )) {
75
+ if (verbose || Preferences .getBoolean ("upload.verbose" ))
76
+ System .out
77
+ .println (_ ("Forcing reset using 1200bps open/close on port " ) +
78
+ uploadPort );
79
+ Serial .touchPort (uploadPort , 1200 );
80
+
81
+ // Scanning for available ports seems to open the port or
82
+ // otherwise assert DTR, which would cancel the WDT reset if
83
+ // it happened within 250 ms. So we wait until the reset should
84
+ // have already occured before we start scanning.
85
+ if (!Base .isMacOS ())
86
+ Thread .sleep (300 );
87
+ }
88
+ // Wait for a port to appear on the list
89
+ int elapsed = 0 ;
90
+ while (elapsed < 10000 ) {
91
+ List <String > now = Serial .list ();
92
+ List <String > diff = new ArrayList <String >(now );
93
+ diff .removeAll (before );
94
+ if (verbose || Preferences .getBoolean ("upload.verbose" )) {
95
+ System .out .print ("PORTS {" );
96
+ for (String p : before )
97
+ System .out .print (p + ", " );
98
+ System .out .print ("} / {" );
99
+ for (String p : now )
100
+ System .out .print (p + ", " );
101
+ System .out .print ("} => {" );
102
+ for (String p : diff )
103
+ System .out .print (p + ", " );
104
+ System .out .println ("}" );
105
+ }
106
+ if (diff .size () > 0 ) {
107
+ caterinaUploadPort = diff .get (0 );
108
+ if (verbose || Preferences .getBoolean ("upload.verbose" ))
109
+ System .out .println ("Found Leonardo upload port: " +
110
+ caterinaUploadPort );
111
+ break ;
112
+ }
113
+
114
+ // Keep track of port that disappears
115
+ before = now ;
116
+ Thread .sleep (250 );
117
+ elapsed += 250 ;
118
+
119
+ // On Windows, it can take a long time for the port to disappear and
120
+ // come back, so use a longer time out before assuming that the
121
+ // selected
122
+ // port is the bootloader (not the sketch).
123
+ if (((!Base .isWindows () && elapsed >= 500 ) || elapsed >= 5000 ) &&
124
+ now .contains (uploadPort )) {
125
+ if (verbose || Preferences .getBoolean ("upload.verbose" ))
126
+ System .out
127
+ .println ("Uploading using selected port: " + uploadPort );
128
+ caterinaUploadPort = uploadPort ;
129
+ break ;
130
+ }
131
+ }
132
+ if (caterinaUploadPort == null )
133
+ // Something happened while detecting port
134
+ throw new RunnerException (
135
+ _ ("Couldn’t find a Leonardo on the selected port. Check that you have the correct port selected. If it is correct, try pressing the board's reset button after initiating the upload." ));
53
136
137
+ uploadPort = caterinaUploadPort ;
138
+ } catch (SerialException e ) {
139
+ throw new RunnerException (e .getMessage ());
140
+ } catch (InterruptedException e ) {
141
+ throw new RunnerException (e .getMessage ());
142
+ }
143
+ prefs .put ("serial.port" , uploadPort );
144
+ }
145
+
54
146
prefs .put ("build.path" , buildPath );
55
147
prefs .put ("build.project_name" , className );
56
148
if (verbose )
57
149
prefs .put ("upload.verbose" , prefs .get ("upload.params.verbose" ));
58
150
else
59
151
prefs .put ("upload.verbose" , prefs .get ("upload.params.quiet" ));
60
152
153
+ boolean uploadResult ;
61
154
try {
62
155
// if (prefs.get("upload.disable_flushing") == null
63
156
// || prefs.get("upload.disable_flushing").toLowerCase().equals("false")) {
@@ -66,10 +159,29 @@ public boolean uploadUsingPreferences(String buildPath, String className,
66
159
67
160
String pattern = prefs .get ("upload.pattern" );
68
161
String [] cmd = StringReplacer .formatAndSplit (pattern , prefs , true );
69
- return executeUploadCommand (cmd );
162
+ uploadResult = executeUploadCommand (cmd );
70
163
} catch (Exception e ) {
71
164
throw new RunnerException (e );
72
165
}
166
+
167
+ // For Leonardo wait until the bootloader serial port disconnects and the
168
+ // sketch serial port reconnects (or timeout after a few seconds if the
169
+ // sketch port never comes back). Doing this saves users from accidentally
170
+ // opening Serial Monitor on the soon-to-be-orphaned bootloader port.
171
+ try {
172
+ if (uploadResult && doTouch ) {
173
+ Thread .sleep (500 );
174
+ long timeout = System .currentTimeMillis () + 2000 ;
175
+ while (timeout > System .currentTimeMillis ()) {
176
+ List <String > portList = Serial .list ();
177
+ if (portList .contains (Preferences .get ("serial.port" )))
178
+ break ;
179
+ Thread .sleep (100 );
180
+ }
181
+ }
182
+ } catch (InterruptedException ex ) {
183
+ }
184
+ return uploadResult ;
73
185
}
74
186
75
187
public boolean uploadUsingProgrammer (String buildPath , String className )
0 commit comments