29
29
30
30
package cc .arduino .packages .discoverers ;
31
31
32
- import java .util .ArrayList ;
33
- import java .util .LinkedList ;
34
- import java .util .List ;
32
+ import static processing .app .I18n .format ;
33
+
35
34
import java .io .InputStream ;
36
35
import java .io .OutputStream ;
36
+ import java .util .ArrayList ;
37
+ import java .util .List ;
37
38
38
- import cc .arduino .packages .BoardPort ;
39
- import cc .arduino .packages .Discovery ;
40
- import processing .app .legacy .PApplet ;
41
-
42
- import com .fasterxml .jackson .databind .ObjectMapper ;
43
- import com .fasterxml .jackson .databind .DeserializationFeature ;
39
+ import com .fasterxml .jackson .annotation .JsonAutoDetect .Visibility ;
40
+ import com .fasterxml .jackson .annotation .PropertyAccessor ;
44
41
import com .fasterxml .jackson .core .JsonFactory ;
45
42
import com .fasterxml .jackson .core .JsonParser ;
46
- import com .fasterxml .jackson .annotation .PropertyAccessor ;
47
- import com .fasterxml .jackson .annotation .JsonAutoDetect .Visibility ;
43
+ import com .fasterxml .jackson .core .JsonProcessingException ;
44
+ import com .fasterxml .jackson .databind .DeserializationFeature ;
45
+ import com .fasterxml .jackson .databind .JsonNode ;
46
+ import com .fasterxml .jackson .databind .ObjectMapper ;
47
+
48
+ import cc .arduino .packages .BoardPort ;
49
+ import cc .arduino .packages .Discovery ;
50
+ import processing .app .PreferencesData ;
51
+ import processing .app .helpers .StringUtils ;
48
52
49
53
public class PluggableDiscovery implements Discovery {
50
54
51
55
private final String discoveryName ;
52
56
private final String [] cmd ;
53
- private final List <BoardPort > portList ;
57
+ private final List <BoardPort > portList = new ArrayList <>() ;
54
58
private Process program =null ;
55
59
private Thread pollingThread ;
56
60
61
+ private void debug (String x ) {
62
+ if (PreferencesData .getBoolean ("discovery.debug" ))
63
+ System .out .println (discoveryName + ": " + x );
64
+ }
65
+
57
66
public PluggableDiscovery (String discoveryName , String [] cmd ) {
58
67
this .cmd = cmd ;
59
68
this .discoveryName = discoveryName ;
60
- portList = new LinkedList <>();
61
- System .out .println (discoveryName + ": Starting: " + PApplet .join (cmd , " " ));
62
69
}
63
70
64
71
@ Override
@@ -76,30 +83,23 @@ public void run() {
76
83
mapper .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
77
84
78
85
while (program != null && program .isAlive ()) {
79
- PluggableDiscoveryMessage msg = mapper .readValue (parser , PluggableDiscoveryMessage .class );
80
- if (msg != null ) {
81
- System .out .println (discoveryName + ": received json: " + msg .getPrefs ());
82
- String event = msg .getEventType ();
83
- if (event != null ) {
84
- if (event .equals ("Error: START_SYNC not supported" )) {
85
- if (pollingThread == null ) {
86
- startPolling ();
87
- }
88
- } else {
89
- if (event .equals ("add" )) {
90
- msg .searchMatchingBoard ();
91
- }
92
- update (msg );
93
- }
86
+ JsonNode tree = mapper .readTree (parser );
87
+ if (tree == null ) {
88
+ if (program != null && program .isAlive ()) {
89
+ System .err .println (format ("{0}: Invalid json message" , discoveryName ));
94
90
}
91
+ break ;
95
92
}
93
+ debug ("Received json: " + tree );
94
+
95
+ processJsonNode (mapper , tree );
96
96
}
97
- System . out . println ( discoveryName + ": thread exit normally" );
97
+ debug ( " thread exit normally" );
98
98
} catch (InterruptedException e ) {
99
- System . out . println ( discoveryName + ": thread exit by interrupt" );
99
+ debug ( " thread exit by interrupt" );
100
100
e .printStackTrace ();
101
101
} catch (Exception e ) {
102
- System . out . println ( discoveryName + ": thread exit other exception" );
102
+ debug ( " thread exit other exception" );
103
103
e .printStackTrace ();
104
104
}
105
105
try {
@@ -108,15 +108,89 @@ public void run() {
108
108
}
109
109
}
110
110
111
+ private void processJsonNode (ObjectMapper mapper , JsonNode node ) {
112
+ JsonNode eventTypeNode = node .get ("eventType" );
113
+ if (eventTypeNode == null ) {
114
+ System .err .println (format ("{0}: Invalid message, missing eventType" , discoveryName ));
115
+ return ;
116
+ }
117
+
118
+ switch (eventTypeNode .asText ()) {
119
+ case "error" :
120
+ try {
121
+ PluggableDiscoveryMessage msg = mapper .treeToValue (node , PluggableDiscoveryMessage .class );
122
+ debug ("error: " + msg .getMessage ());
123
+ if (msg .getMessage ().contains ("START_SYNC" )) {
124
+ startPolling ();
125
+ }
126
+ } catch (JsonProcessingException e ) {
127
+ e .printStackTrace ();
128
+ }
129
+ return ;
130
+
131
+ case "list" :
132
+ JsonNode portsNode = node .get ("ports" );
133
+ if (portsNode == null ) {
134
+ System .err .println (format ("{0}: Invalid message, missing ports list" , discoveryName ));
135
+ return ;
136
+ }
137
+ if (!portsNode .isArray ()) {
138
+ System .err .println (format ("{0}: Invalid message, ports list should be an array" , discoveryName ));
139
+ return ;
140
+ }
141
+
142
+ portList .clear ();
143
+ portsNode .forEach (portNode -> {
144
+ try {
145
+ BoardPort port = mapper .treeToValue (portNode , BoardPort .class );
146
+ port .searchMatchingBoard ();
147
+ addOrUpdate (port );
148
+ } catch (JsonProcessingException e ) {
149
+ System .err .println (format ("{0}: Invalid BoardPort message" , discoveryName ));
150
+ e .printStackTrace ();
151
+ }
152
+ });
153
+ return ;
154
+
155
+ // Messages for SYNC updates
156
+
157
+ case "add" :
158
+ try {
159
+ BoardPort port = mapper .treeToValue (node , BoardPort .class );
160
+ port .searchMatchingBoard ();
161
+ addOrUpdate (port );
162
+ } catch (JsonProcessingException e ) {
163
+ System .err .println (format ("{0}: Invalid BoardPort message" , discoveryName ));
164
+ e .printStackTrace ();
165
+ }
166
+ return ;
167
+
168
+ case "remove" :
169
+ try {
170
+ BoardPort port = mapper .treeToValue (node , BoardPort .class );
171
+ remove (port );
172
+ } catch (JsonProcessingException e ) {
173
+ System .err .println (format ("{0}: Invalid BoardPort message" , discoveryName ));
174
+ e .printStackTrace ();
175
+ }
176
+ return ;
177
+
178
+ default :
179
+ debug ("Invalid event: " + eventTypeNode .asText ());
180
+ return ;
181
+ }
182
+ }
183
+
111
184
@ Override
112
185
public void start () throws Exception {
113
- System .out .println (discoveryName + ": start" );
114
186
try {
187
+ debug ("Starting: " + StringUtils .join (cmd , " " ));
115
188
program = Runtime .getRuntime ().exec (cmd );
116
189
} catch (Exception e ) {
117
190
program = null ;
118
191
return ;
119
192
}
193
+ debug ("START_SYNC" );
120
194
write ("START_SYNC\n " );
121
195
pollingThread = null ;
122
196
}
@@ -126,11 +200,13 @@ private void startPolling() {
126
200
// LIST command. A second thread is created to send these
127
201
// commands, while the run() thread above listens for the
128
202
// discovery tool output.
203
+ debug ("START" );
129
204
write ("START\n " );
130
205
Thread pollingThread = new Thread () {
131
206
public void run () {
132
207
try {
133
208
while (program != null && program .isAlive ()) {
209
+ debug ("LIST" );
134
210
write ("LIST\n " );
135
211
sleep (2500 );
136
212
}
@@ -165,37 +241,32 @@ private void write(String command) {
165
241
}
166
242
}
167
243
168
- private synchronized void update ( PluggableDiscoveryMessage port ) {
244
+ private synchronized void addOrUpdate ( BoardPort port ) {
169
245
// Update the list of discovered ports, which may involve
170
246
// adding a new port, replacing the info for a previously
171
247
// discovered port, or removing a port. This function
172
248
// must be synchronized with listDiscoveredBoards(), to
173
249
// avoid changing the list while it's being accessed by
174
250
// another thread.
175
251
String address = port .getAddress ();
176
- if (address == null ) return ; // address required for "add" & "remove"
177
- for (BoardPort bp : portList ) {
178
- if (address .equals (bp .getAddress ())) {
179
- // if address already on the list, discard old info
180
- portList .remove (bp );
181
- }
182
- }
183
- if (port .getEventType ().equals ("add" )) {
184
- if (port .getLabel () == null ) {
185
- // if no label, use address & name, or just address if no name
186
- String name = port .getBoardName ();
187
- if (name == null ) {
188
- port .setLabel (address );
189
- } else {
190
- port .setLabel (address + " (" + name + ")" );
191
- }
192
- }
193
- if (port .getProtocol () == null ) {
194
- // if no protocol, assume serial
195
- port .setProtocol ("serial" );
196
- }
197
- portList .add (port );
252
+ if (address == null )
253
+ return ; // address required for "add" & "remove"
254
+
255
+ // if address already on the list, discard old info
256
+ portList .removeIf (bp -> address .equals (bp .getAddress ()));
257
+
258
+ // if no label, use address
259
+ if (port .getLabel () == null ) {
260
+ port .setLabel (address );
198
261
}
262
+ portList .add (port );
263
+ }
264
+
265
+ private synchronized void remove (BoardPort port ) {
266
+ String address = port .getAddress ();
267
+ if (address == null )
268
+ return ; // address required for "add" & "remove"
269
+ portList .removeIf (bp -> address .equals (bp .getAddress ()));
199
270
}
200
271
201
272
@ Override
@@ -205,18 +276,14 @@ public synchronized List<BoardPort> listDiscoveredBoards() {
205
276
// returned for use by the rest of the IDE. This copy
206
277
// operation must be synchronized with update() to assure
207
278
// a clean copy.
208
- final List <BoardPort > portListCopy = new ArrayList <>();
209
- for (BoardPort bp : portList ) {
210
- portListCopy .add (new BoardPort (bp ));
211
- }
212
- return portListCopy ;
279
+ return new ArrayList <>(portList );
213
280
}
214
281
215
282
@ Override
216
283
public List <BoardPort > listDiscoveredBoards (boolean complete ) {
217
284
// XXX: parameter "complete "is really needed?
218
285
// should be checked on all existing discoveries
219
- return listDiscoveredBoards ( );
286
+ return new ArrayList <>( portList );
220
287
}
221
288
222
289
@ Override
0 commit comments