@@ -42,6 +42,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
42
42
protected readonly onAvailableBoardsChangedEmitter = new Emitter <
43
43
AvailableBoard [ ]
44
44
> ( ) ;
45
+ protected readonly onAvailablePortsChangedEmitter = new Emitter < Port [ ] > ( ) ;
45
46
46
47
/**
47
48
* 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 {
67
68
* This event is also emitted when the board package for the currently selected board was uninstalled.
68
69
*/
69
70
readonly onBoardsConfigChanged = this . onBoardsConfigChangedEmitter . event ;
70
- readonly onAvailableBoardsChanged =
71
- this . onAvailableBoardsChangedEmitter . event ;
71
+ readonly onAvailableBoardsChanged = this . onAvailableBoardsChangedEmitter . event ;
72
+ readonly onAvailablePortsChanged = this . onAvailablePortsChangedEmitter . event ;
72
73
73
74
onStart ( ) : void {
74
75
this . notificationCenter . onAttachedBoardsChanged (
@@ -88,6 +89,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
88
89
] ) . then ( ( [ attachedBoards , availablePorts ] ) => {
89
90
this . _attachedBoards = attachedBoards ;
90
91
this . _availablePorts = availablePorts ;
92
+ this . onAvailablePortsChangedEmitter . fire ( this . _availablePorts ) ;
91
93
this . reconcileAvailableBoards ( ) . then ( ( ) => this . tryReconnect ( ) ) ;
92
94
} ) ;
93
95
}
@@ -102,6 +104,7 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
102
104
}
103
105
this . _attachedBoards = event . newState . boards ;
104
106
this . _availablePorts = event . newState . ports ;
107
+ this . onAvailablePortsChangedEmitter . fire ( this . _availablePorts ) ;
105
108
this . reconcileAvailableBoards ( ) . then ( ( ) => this . tryReconnect ( ) ) ;
106
109
}
107
110
@@ -180,8 +183,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
180
183
const selectedAvailableBoard = AvailableBoard . is ( selectedBoard )
181
184
? selectedBoard
182
185
: this . _availableBoards . find ( ( availableBoard ) =>
183
- Board . sameAs ( availableBoard , selectedBoard )
184
- ) ;
186
+ Board . sameAs ( availableBoard , selectedBoard )
187
+ ) ;
185
188
if (
186
189
selectedAvailableBoard &&
187
190
selectedAvailableBoard . selected &&
@@ -358,14 +361,14 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
358
361
const timeoutTask =
359
362
! ! timeout && timeout > 0
360
363
? 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
365
367
)
368
+ )
366
369
: new Promise < void > ( ( ) => {
367
- /* never */
368
- } ) ;
370
+ /* never */
371
+ } ) ;
369
372
const waitUntilTask = new Promise < void > ( ( resolve ) => {
370
373
let candidate = find ( what , this . availableBoards ) ;
371
374
if ( candidate ) {
@@ -384,7 +387,6 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
384
387
}
385
388
386
389
protected async reconcileAvailableBoards ( ) : Promise < void > {
387
- const attachedBoards = this . _attachedBoards ;
388
390
const availablePorts = this . _availablePorts ;
389
391
// Unset the port on the user's config, if it is not available anymore.
390
392
if (
@@ -402,51 +404,64 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
402
404
const boardsConfig = this . boardsConfig ;
403
405
const currentAvailableBoards = this . _availableBoards ;
404
406
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
+ } ) ;
407
425
408
426
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 ;
413
431
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 ) {
416
439
// If the selected board is not recognized because it is a 3rd party board: https://github.com/arduino/arduino-cli/issues/623
417
440
// 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 ) ,
432
445
port : boardPort ,
433
- state,
434
- } ) ;
446
+ } ;
435
447
} 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' ) ,
441
450
port : boardPort ,
442
- } ) ;
451
+ state : AvailableBoard . State . incomplete ,
452
+ } ;
443
453
}
454
+ availableBoards . push ( availableBoard ) ;
444
455
}
445
456
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
+ }
450
465
availableBoards . push ( {
451
466
...boardsConfig . selectedBoard ,
452
467
port : boardsConfig . selectedPort ,
@@ -455,28 +470,20 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
455
470
} ) ;
456
471
}
457
472
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 ;
467
479
}
468
480
if ( hasChanged ) {
469
- this . _availableBoards = sortedAvailableBoards ;
481
+ this . _availableBoards = availableBoards ;
470
482
this . onAvailableBoardsChangedEmitter . fire ( this . _availableBoards ) ;
471
483
}
472
484
}
473
485
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 > {
480
487
const key = this . getLastSelectedBoardOnPortKey ( port ) ;
481
488
return this . getData < Board > ( key ) ;
482
489
}
@@ -497,11 +504,8 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
497
504
] ) ;
498
505
}
499
506
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 ) } ` ;
505
509
}
506
510
507
511
protected async loadState ( ) : Promise < void > {
@@ -585,35 +589,30 @@ export namespace AvailableBoard {
585
589
return ! ! board . port ;
586
590
}
587
591
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
588
598
export const compare = ( left : AvailableBoard , right : AvailableBoard ) => {
589
- if ( left . selected && ! right . selected ) {
599
+ if ( left . port ?. protocol === "serial" && right . port ?. protocol !== "serial" ) {
590
600
return - 1 ;
591
- }
592
- if ( right . selected && ! left . selected ) {
601
+ } else if ( left . port ?. protocol !== "serial" && right . port ?. protocol === "serial" ) {
593
602
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" ) {
612
604
return - 1 ;
613
- }
614
- if ( ! ! right . selected && ! left . selected ) {
605
+ } else if ( left . port ?. protocol !== "network" && right . port ?. protocol === "network" ) {
615
606
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
+ }
616
615
}
617
- return left . state - right . state ;
618
- } ;
616
+ return naturalCompare ( left . port ?. address ! , right . port ?. address ! ) ;
617
+ }
619
618
}
0 commit comments