2929
3030package cc .arduino .packages .discoverers ;
3131
32- import java .util .ArrayList ;
33- import java .util .LinkedList ;
34- import java .util .List ;
32+ import static processing .app .I18n .format ;
33+
3534import java .io .InputStream ;
3635import java .io .OutputStream ;
36+ import java .util .ArrayList ;
37+ import java .util .List ;
3738
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 ;
4441import com .fasterxml .jackson .core .JsonFactory ;
4542import 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 ;
4852
4953public class PluggableDiscovery implements Discovery {
5054
5155 private final String discoveryName ;
5256 private final String [] cmd ;
53- private final List <BoardPort > portList ;
57+ private final List <BoardPort > portList = new ArrayList <>() ;
5458 private Process program =null ;
5559 private Thread pollingThread ;
5660
61+ private void debug (String x ) {
62+ if (PreferencesData .getBoolean ("discovery.debug" ))
63+ System .out .println (discoveryName + ": " + x );
64+ }
65+
5766 public PluggableDiscovery (String discoveryName , String [] cmd ) {
5867 this .cmd = cmd ;
5968 this .discoveryName = discoveryName ;
60- portList = new LinkedList <>();
61- System .out .println (discoveryName + ": Starting: " + PApplet .join (cmd , " " ));
6269 }
6370
6471 @ Override
@@ -76,30 +83,23 @@ public void run() {
7683 mapper .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
7784
7885 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 ));
9490 }
91+ break ;
9592 }
93+ debug ("Received json: " + tree );
94+
95+ processJsonNode (mapper , tree );
9696 }
97- System . out . println ( discoveryName + ": thread exit normally" );
97+ debug ( " thread exit normally" );
9898 } catch (InterruptedException e ) {
99- System . out . println ( discoveryName + ": thread exit by interrupt" );
99+ debug ( " thread exit by interrupt" );
100100 e .printStackTrace ();
101101 } catch (Exception e ) {
102- System . out . println ( discoveryName + ": thread exit other exception" );
102+ debug ( " thread exit other exception" );
103103 e .printStackTrace ();
104104 }
105105 try {
@@ -108,15 +108,89 @@ public void run() {
108108 }
109109 }
110110
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+
111184 @ Override
112185 public void start () throws Exception {
113- System .out .println (discoveryName + ": start" );
114186 try {
187+ debug ("Starting: " + StringUtils .join (cmd , " " ));
115188 program = Runtime .getRuntime ().exec (cmd );
116189 } catch (Exception e ) {
117190 program = null ;
118191 return ;
119192 }
193+ debug ("START_SYNC" );
120194 write ("START_SYNC\n " );
121195 pollingThread = null ;
122196 }
@@ -126,11 +200,13 @@ private void startPolling() {
126200 // LIST command. A second thread is created to send these
127201 // commands, while the run() thread above listens for the
128202 // discovery tool output.
203+ debug ("START" );
129204 write ("START\n " );
130205 Thread pollingThread = new Thread () {
131206 public void run () {
132207 try {
133208 while (program != null && program .isAlive ()) {
209+ debug ("LIST" );
134210 write ("LIST\n " );
135211 sleep (2500 );
136212 }
@@ -165,37 +241,32 @@ private void write(String command) {
165241 }
166242 }
167243
168- private synchronized void update ( PluggableDiscoveryMessage port ) {
244+ private synchronized void addOrUpdate ( BoardPort port ) {
169245 // Update the list of discovered ports, which may involve
170246 // adding a new port, replacing the info for a previously
171247 // discovered port, or removing a port. This function
172248 // must be synchronized with listDiscoveredBoards(), to
173249 // avoid changing the list while it's being accessed by
174250 // another thread.
175251 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 );
198261 }
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 ()));
199270 }
200271
201272 @ Override
@@ -205,18 +276,14 @@ public synchronized List<BoardPort> listDiscoveredBoards() {
205276 // returned for use by the rest of the IDE. This copy
206277 // operation must be synchronized with update() to assure
207278 // 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 );
213280 }
214281
215282 @ Override
216283 public List <BoardPort > listDiscoveredBoards (boolean complete ) {
217284 // XXX: parameter "complete "is really needed?
218285 // should be checked on all existing discoveries
219- return listDiscoveredBoards ( );
286+ return new ArrayList <>( portList );
220287 }
221288
222289 @ Override
0 commit comments