1
1
import { injectable , inject , postConstruct } from 'inversify' ;
2
- import { Emitter , ILogger } from '@theia/core' ;
3
- import { BoardsServiceClient , AttachedBoardsChangeEvent , BoardInstalledEvent , AttachedSerialBoard } from '../../common/protocol/boards-service' ;
2
+ import { Emitter } from '@theia/core/lib/common/event' ;
3
+ import { ILogger } from '@theia/core/lib/common/logger' ;
4
+ import { LocalStorageService } from '@theia/core/lib/browser/storage-service' ;
5
+ import { RecursiveRequired } from '../../common/types' ;
6
+ import { BoardsServiceClient , AttachedBoardsChangeEvent , BoardInstalledEvent , AttachedSerialBoard , Board } from '../../common/protocol/boards-service' ;
4
7
import { BoardsConfig } from './boards-config' ;
5
- import { LocalStorageService } from '@theia/core/lib/browser ' ;
8
+ import { MaybePromise } from '@theia/core' ;
6
9
7
10
@injectable ( )
8
11
export class BoardsServiceClientImpl implements BoardsServiceClient {
@@ -13,10 +16,18 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
13
16
@inject ( LocalStorageService )
14
17
protected storageService : LocalStorageService ;
15
18
16
- protected readonly onAttachedBoardsChangedEmitter = new Emitter < AttachedBoardsChangeEvent > ( ) ;
17
19
protected readonly onBoardInstalledEmitter = new Emitter < BoardInstalledEvent > ( ) ;
20
+ protected readonly onAttachedBoardsChangedEmitter = new Emitter < AttachedBoardsChangeEvent > ( ) ;
18
21
protected readonly onSelectedBoardsConfigChangedEmitter = new Emitter < BoardsConfig . Config > ( ) ;
19
22
23
+ /**
24
+ * Used for the auto-reconnecting. Sometimes, the attached board gets disconnected after uploading something to it.
25
+ * It happens with certain boards on Windows. For example, the `MKR1000` boards is selected on post `COM5` on Windows,
26
+ * perform an upload, the board automatically disconnects and reconnects, but on another port, `COM10`.
27
+ * We have to listen on such changes and auto-reconnect the same board on another port.
28
+ * See: https://arduino.slack.com/archives/CJJHJCJSJ/p1568645417013000?thread_ts=1568640504.009400&cid=CJJHJCJSJ
29
+ */
30
+ protected latestValidBoardsConfig : RecursiveRequired < BoardsConfig . Config > | undefined = undefined ;
20
31
protected _boardsConfig : BoardsConfig . Config = { } ;
21
32
22
33
readonly onBoardsChanged = this . onAttachedBoardsChangedEmitter . event ;
@@ -30,7 +41,8 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
30
41
31
42
notifyAttachedBoardsChanged ( event : AttachedBoardsChangeEvent ) : void {
32
43
this . logger . info ( 'Attached boards changed: ' , JSON . stringify ( event ) ) ;
33
- const detachedBoards = AttachedBoardsChangeEvent . diff ( event ) . detached . filter ( AttachedSerialBoard . is ) . map ( ( { port } ) => port ) ;
44
+ const { detached, attached } = AttachedBoardsChangeEvent . diff ( event ) ;
45
+ const detachedBoards = detached . filter ( AttachedSerialBoard . is ) . map ( ( { port } ) => port ) ;
34
46
const { selectedPort, selectedBoard } = this . boardsConfig ;
35
47
this . onAttachedBoardsChangedEmitter . fire ( event ) ;
36
48
// Dynamically unset the port if the selected board was an attached one and we detached it.
@@ -40,6 +52,37 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
40
52
selectedPort : undefined
41
53
} ;
42
54
}
55
+ // Try to reconnect.
56
+ this . tryReconnect ( attached ) ;
57
+ }
58
+
59
+ async tryReconnect ( attachedBoards : MaybePromise < Array < Board > > ) : Promise < boolean > {
60
+ const boards = await attachedBoards ;
61
+ if ( this . latestValidBoardsConfig && ! this . canUploadTo ( this . boardsConfig ) ) {
62
+ for ( const board of boards . filter ( AttachedSerialBoard . is ) ) {
63
+ if ( this . latestValidBoardsConfig . selectedBoard . fqbn === board . fqbn
64
+ && this . latestValidBoardsConfig . selectedBoard . name === board . name
65
+ && this . latestValidBoardsConfig . selectedPort === board . port ) {
66
+
67
+ this . boardsConfig = this . latestValidBoardsConfig ;
68
+ return true ;
69
+ }
70
+ }
71
+ // If we could not find an exact match, we compare the board FQBN-name pairs and ignore the port, as it might have changed.
72
+ // See documentation on `latestValidBoardsConfig`.
73
+ for ( const board of boards . filter ( AttachedSerialBoard . is ) ) {
74
+ if ( this . latestValidBoardsConfig . selectedBoard . fqbn === board . fqbn
75
+ && this . latestValidBoardsConfig . selectedBoard . name === board . name ) {
76
+
77
+ this . boardsConfig = {
78
+ ...this . latestValidBoardsConfig ,
79
+ selectedPort : board . port
80
+ } ;
81
+ return true ;
82
+ }
83
+ }
84
+ }
85
+ return false ;
43
86
}
44
87
45
88
notifyBoardInstalled ( event : BoardInstalledEvent ) : void {
@@ -50,6 +93,9 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
50
93
set boardsConfig ( config : BoardsConfig . Config ) {
51
94
this . logger . info ( 'Board config changed: ' , JSON . stringify ( config ) ) ;
52
95
this . _boardsConfig = config ;
96
+ if ( this . canUploadTo ( this . _boardsConfig ) ) {
97
+ this . latestValidBoardsConfig = this . _boardsConfig ;
98
+ }
53
99
this . saveState ( ) . then ( ( ) => this . onSelectedBoardsConfigChangedEmitter . fire ( this . _boardsConfig ) ) ;
54
100
}
55
101
@@ -58,14 +104,22 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
58
104
}
59
105
60
106
protected saveState ( ) : Promise < void > {
61
- return this . storageService . setData ( 'boards-config' , this . boardsConfig ) ;
107
+ return this . storageService . setData ( 'latest-valid- boards-config' , this . latestValidBoardsConfig ) ;
62
108
}
63
109
64
110
protected async loadState ( ) : Promise < void > {
65
- const boardsConfig = await this . storageService . getData < BoardsConfig . Config > ( ' boards-config') ;
66
- if ( boardsConfig ) {
67
- this . boardsConfig = boardsConfig ;
111
+ const storedValidBoardsConfig = await this . storageService . getData < RecursiveRequired < BoardsConfig . Config > > ( 'latest-valid- boards-config') ;
112
+ if ( storedValidBoardsConfig ) {
113
+ this . latestValidBoardsConfig = storedValidBoardsConfig ;
68
114
}
69
115
}
70
116
117
+ protected canVerify ( config : BoardsConfig . Config | undefined ) : config is BoardsConfig . Config & { selectedBoard : Board } {
118
+ return ! ! config && ! ! config . selectedBoard ;
119
+ }
120
+
121
+ protected canUploadTo ( config : BoardsConfig . Config | undefined ) : config is RecursiveRequired < BoardsConfig . Config > {
122
+ return this . canVerify ( config ) && ! ! config . selectedPort && ! ! config . selectedBoard . fqbn ;
123
+ }
124
+
71
125
}
0 commit comments