@@ -42,6 +42,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
4242 protected readonly onAvailableBoardsChangedEmitter = new Emitter <
4343 AvailableBoard [ ]
4444 > ( ) ;
45+ protected readonly onAvailablePortsChangedEmitter = new Emitter < Port [ ] > ( ) ;
4546
4647 /**
4748 * Used for the auto-reconnecting. Sometimes, the attached board gets disconnected after uploading something to it.
@@ -67,8 +68,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
6768 * This event is also emitted when the board package for the currently selected board was uninstalled.
6869 */
6970 readonly onBoardsConfigChanged = this . onBoardsConfigChangedEmitter . event ;
70- readonly onAvailableBoardsChanged =
71- this . onAvailableBoardsChangedEmitter . event ;
71+ readonly onAvailableBoardsChanged = this . onAvailableBoardsChangedEmitter . event ;
72+ readonly onAvailablePortsChanged = this . onAvailablePortsChangedEmitter . event ;
7273
7374 onStart ( ) : void {
7475 this . notificationCenter . onAttachedBoardsChanged (
@@ -88,6 +89,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
8889 ] ) . then ( ( [ attachedBoards , availablePorts ] ) => {
8990 this . _attachedBoards = attachedBoards ;
9091 this . _availablePorts = availablePorts ;
92+ this . onAvailablePortsChangedEmitter . fire ( this . _availablePorts ) ;
9193 this . reconcileAvailableBoards ( ) . then ( ( ) => this . tryReconnect ( ) ) ;
9294 } ) ;
9395 }
@@ -102,6 +104,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
102104 }
103105 this . _attachedBoards = event . newState . boards ;
104106 this . _availablePorts = event . newState . ports ;
107+ this . onAvailablePortsChangedEmitter . fire ( this . _availablePorts ) ;
105108 this . reconcileAvailableBoards ( ) . then ( ( ) => this . tryReconnect ( ) ) ;
106109 }
107110
@@ -180,8 +183,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
180183 const selectedAvailableBoard = AvailableBoard . is ( selectedBoard )
181184 ? selectedBoard
182185 : this . _availableBoards . find ( ( availableBoard ) =>
183- Board . sameAs ( availableBoard , selectedBoard )
184- ) ;
186+ Board . sameAs ( availableBoard , selectedBoard )
187+ ) ;
185188 if (
186189 selectedAvailableBoard &&
187190 selectedAvailableBoard . selected &&
@@ -358,14 +361,14 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
358361 const timeoutTask =
359362 ! ! timeout && timeout > 0
360363 ? new Promise < void > ( ( _ , reject ) =>
361- setTimeout (
362- ( ) => reject ( new Error ( `Timeout after ${ timeout } ms.` ) ) ,
363- timeout
364- )
364+ setTimeout (
365+ ( ) => reject ( new Error ( `Timeout after ${ timeout } ms.` ) ) ,
366+ timeout
365367 )
368+ )
366369 : new Promise < void > ( ( ) => {
367- /* never */
368- } ) ;
370+ /* never */
371+ } ) ;
369372 const waitUntilTask = new Promise < void > ( ( resolve ) => {
370373 let candidate = find ( what , this . availableBoards ) ;
371374 if ( candidate ) {
@@ -384,7 +387,6 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
384387 }
385388
386389 protected async reconcileAvailableBoards ( ) : Promise < void > {
387- const attachedBoards = this . _attachedBoards ;
388390 const availablePorts = this . _availablePorts ;
389391 // Unset the port on the user's config, if it is not available anymore.
390392 if (
@@ -402,51 +404,64 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
402404 const boardsConfig = this . boardsConfig ;
403405 const currentAvailableBoards = this . _availableBoards ;
404406 const availableBoards : AvailableBoard [ ] = [ ] ;
405- const availableBoardPorts = availablePorts . filter ( Port . isBoardPort ) ;
406- const attachedSerialBoards = attachedBoards . filter ( ( { port } ) => ! ! port ) ;
407+ const attachedBoards = this . _attachedBoards . filter ( ( { port } ) => ! ! port ) ;
408+ const availableBoardPorts = availablePorts . filter ( ( port ) => {
409+ if ( port . protocol === "serial" ) {
410+ // We always show all serial ports, even if there
411+ // is no recognized board connected to it
412+ return true ;
413+ }
414+
415+ // All other ports with different protocol are
416+ // only shown if there is a recognized board
417+ // connected
418+ for ( const board of attachedBoards ) {
419+ if ( board . port ?. address === port . address ) {
420+ return true ;
421+ }
422+ }
423+ return false ;
424+ } ) ;
407425
408426 for ( const boardPort of availableBoardPorts ) {
409- let state = AvailableBoard . State . incomplete ; // Initial pessimism.
410- let board = attachedSerialBoards . find ( ( { port } ) =>
411- Port . sameAs ( boardPort , port )
412- ) ;
427+ let board = attachedBoards . find ( ( { port } ) => Port . sameAs ( boardPort , port ) ) ;
428+ const lastSelectedBoard = await this . getLastSelectedBoardOnPort ( boardPort ) ;
429+
430+ let availableBoard = { } as AvailableBoard ;
413431 if ( board ) {
414- state = AvailableBoard . State . recognized ;
415- } else {
432+ availableBoard = {
433+ ...board ,
434+ state : AvailableBoard . State . recognized ,
435+ selected : BoardsConfig . Config . sameAs ( boardsConfig , board ) ,
436+ port : boardPort ,
437+ } ;
438+ } else if ( lastSelectedBoard ) {
416439 // If the selected board is not recognized because it is a 3rd party board: https://github.com/arduino/arduino-cli/issues/623
417440 // We still want to show it without the red X in the boards toolbar: https://github.com/arduino/arduino-pro-ide/issues/198#issuecomment-599355836
418- const lastSelectedBoard = await this . getLastSelectedBoardOnPort (
419- boardPort
420- ) ;
421- if ( lastSelectedBoard ) {
422- board = {
423- ...lastSelectedBoard ,
424- port : boardPort ,
425- } ;
426- state = AvailableBoard . State . guessed ;
427- }
428- }
429- if ( ! board ) {
430- availableBoards . push ( {
431- name : nls . localize ( 'arduino/common/unknown' , 'Unknown' ) ,
441+ availableBoard = {
442+ ...lastSelectedBoard ,
443+ state : AvailableBoard . State . guessed ,
444+ selected : BoardsConfig . Config . sameAs ( boardsConfig , lastSelectedBoard ) ,
432445 port : boardPort ,
433- state,
434- } ) ;
446+ } ;
435447 } else {
436- const selected = BoardsConfig . Config . sameAs ( boardsConfig , board ) ;
437- availableBoards . push ( {
438- ...board ,
439- state,
440- selected,
448+ availableBoard = {
449+ name : nls . localize ( 'arduino/common/unknown' , 'Unknown' ) ,
441450 port : boardPort ,
442- } ) ;
451+ state : AvailableBoard . State . incomplete ,
452+ } ;
443453 }
454+ availableBoards . push ( availableBoard ) ;
444455 }
445456
446- if (
447- boardsConfig . selectedBoard &&
448- ! availableBoards . some ( ( { selected } ) => selected )
449- ) {
457+ if ( boardsConfig . selectedBoard && ! availableBoards . some ( ( { selected } ) => selected ) ) {
458+ // If the selected board has the same port of an unknown board
459+ // that is already in availableBoards we might get a duplicate port.
460+ // So we remove the one already in the array and add the selected one.
461+ const found = availableBoards . findIndex ( board => board . port ?. address === boardsConfig . selectedPort ?. address ) ;
462+ if ( found >= 0 ) {
463+ availableBoards . splice ( found , 1 ) ;
464+ }
450465 availableBoards . push ( {
451466 ...boardsConfig . selectedBoard ,
452467 port : boardsConfig . selectedPort ,
@@ -455,28 +470,20 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
455470 } ) ;
456471 }
457472
458- const sortedAvailableBoards = availableBoards . sort ( AvailableBoard . compare ) ;
459- let hasChanged =
460- sortedAvailableBoards . length !== currentAvailableBoards . length ;
461- for ( let i = 0 ; ! hasChanged && i < sortedAvailableBoards . length ; i ++ ) {
462- hasChanged =
463- AvailableBoard . compare (
464- sortedAvailableBoards [ i ] ,
465- currentAvailableBoards [ i ]
466- ) !== 0 ;
473+ availableBoards . sort ( AvailableBoard . compare ) ;
474+
475+ let hasChanged = availableBoards . length !== currentAvailableBoards . length ;
476+ for ( let i = 0 ; ! hasChanged && i < availableBoards . length ; i ++ ) {
477+ const [ left , right ] = [ availableBoards [ i ] , currentAvailableBoards [ i ] ] ;
478+ hasChanged = ! ! AvailableBoard . compare ( left , right ) || left . selected !== right . selected ;
467479 }
468480 if ( hasChanged ) {
469- this . _availableBoards = sortedAvailableBoards ;
481+ this . _availableBoards = availableBoards ;
470482 this . onAvailableBoardsChangedEmitter . fire ( this . _availableBoards ) ;
471483 }
472484 }
473485
474- protected async getLastSelectedBoardOnPort (
475- port : Port | string | undefined
476- ) : Promise < Board | undefined > {
477- if ( ! port ) {
478- return undefined ;
479- }
486+ protected async getLastSelectedBoardOnPort ( port : Port ) : Promise < Board | undefined > {
480487 const key = this . getLastSelectedBoardOnPortKey ( port ) ;
481488 return this . getData < Board > ( key ) ;
482489 }
@@ -497,11 +504,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
497504 ] ) ;
498505 }
499506
500- protected getLastSelectedBoardOnPortKey ( port : Port | string ) : string {
501- // TODO: we lose the port's `protocol` info (`serial`, `network`, etc.) here if the `port` is a `string`.
502- return `last-selected-board-on-port:${
503- typeof port === 'string' ? port : Port . toString ( port )
504- } `;
507+ protected getLastSelectedBoardOnPortKey ( port : Port ) : string {
508+ return `last-selected-board-on-port:${ Port . toString ( port ) } ` ;
505509 }
506510
507511 protected async loadState ( ) : Promise < void > {
@@ -585,35 +589,30 @@ export namespace AvailableBoard {
585589 return ! ! board . port ;
586590 }
587591
592+ // Available boards must be sorted in this order:
593+ // 1. Serial with recognized boards
594+ // 2. Serial with guessed boards
595+ // 3. Serial with incomplete boards
596+ // 4. Network with recognized boards
597+ // 5. Other protocols with recognized boards
588598 export const compare = ( left : AvailableBoard , right : AvailableBoard ) => {
589- if ( left . selected && ! right . selected ) {
599+ if ( left . port ?. protocol === "serial" && right . port ?. protocol !== "serial" ) {
590600 return - 1 ;
591- }
592- if ( right . selected && ! left . selected ) {
601+ } else if ( left . port ?. protocol !== "serial" && right . port ?. protocol === "serial" ) {
593602 return 1 ;
594- }
595- let result = naturalCompare ( left . name , right . name ) ;
596- if ( result !== 0 ) {
597- return result ;
598- }
599- if ( left . fqbn && right . fqbn ) {
600- result = naturalCompare ( left . fqbn , right . fqbn ) ;
601- if ( result !== 0 ) {
602- return result ;
603- }
604- }
605- if ( left . port && right . port ) {
606- result = Port . compare ( left . port , right . port ) ;
607- if ( result !== 0 ) {
608- return result ;
609- }
610- }
611- if ( ! ! left . selected && ! right . selected ) {
603+ } else if ( left . port ?. protocol === "network" && right . port ?. protocol !== "network" ) {
612604 return - 1 ;
613- }
614- if ( ! ! right . selected && ! left . selected ) {
605+ } else if ( left . port ?. protocol !== "network" && right . port ?. protocol === "network" ) {
615606 return 1 ;
607+ } else if ( left . port ?. protocol === right . port ?. protocol ) {
608+ // We show all ports, including those that have guessed
609+ // or unrecognized boards, so we must sort those too.
610+ if ( left . state < right . state ) {
611+ return - 1 ;
612+ } else if ( left . state > right . state ) {
613+ return 1 ;
614+ }
616615 }
617- return left . state - right . state ;
618- } ;
616+ return naturalCompare ( left . port ?. address ! , right . port ?. address ! ) ;
617+ }
619618}
0 commit comments