Skip to content

Commit 8971dc4

Browse files
author
Akos Kitta
committed
Implemented naive reconnecting.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
1 parent 2be5494 commit 8971dc4

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
137137
@inject(QuickOpenService)
138138
protected readonly quickOpenService: QuickOpenService;
139139

140-
@inject(ArduinoWorkspaceService)
140+
@inject(ArduinoWorkspaceService)
141141
protected readonly workspaceService: ArduinoWorkspaceService;
142142

143143
@inject(ConfigService)
@@ -164,6 +164,8 @@ export class ArduinoFrontendContribution implements TabBarToolbarContribution, C
164164
updateStatusBar(this.boardsServiceClient.boardsConfig);
165165

166166
this.registerSketchesInMenu(this.menuRegistry);
167+
168+
this.boardsService.getAttachedBoards().then(({ boards }) => this.boardsServiceClient.tryReconnect(boards));
167169
}
168170

169171
registerToolbarItems(registry: TabBarToolbarRegistry): void {

arduino-ide-extension/src/browser/boards/boards-service-client-impl.ts

+63-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
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';
47
import { BoardsConfig } from './boards-config';
5-
import { LocalStorageService } from '@theia/core/lib/browser';
8+
import { MaybePromise } from '@theia/core';
69

710
@injectable()
811
export class BoardsServiceClientImpl implements BoardsServiceClient {
@@ -13,10 +16,18 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
1316
@inject(LocalStorageService)
1417
protected storageService: LocalStorageService;
1518

16-
protected readonly onAttachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
1719
protected readonly onBoardInstalledEmitter = new Emitter<BoardInstalledEvent>();
20+
protected readonly onAttachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
1821
protected readonly onSelectedBoardsConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
1922

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;
2031
protected _boardsConfig: BoardsConfig.Config = {};
2132

2233
readonly onBoardsChanged = this.onAttachedBoardsChangedEmitter.event;
@@ -30,7 +41,8 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
3041

3142
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
3243
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);
3446
const { selectedPort, selectedBoard } = this.boardsConfig;
3547
this.onAttachedBoardsChangedEmitter.fire(event);
3648
// 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 {
4052
selectedPort: undefined
4153
};
4254
}
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;
4386
}
4487

4588
notifyBoardInstalled(event: BoardInstalledEvent): void {
@@ -50,6 +93,9 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
5093
set boardsConfig(config: BoardsConfig.Config) {
5194
this.logger.info('Board config changed: ', JSON.stringify(config));
5295
this._boardsConfig = config;
96+
if (this.canUploadTo(this._boardsConfig)) {
97+
this.latestValidBoardsConfig = this._boardsConfig;
98+
}
5399
this.saveState().then(() => this.onSelectedBoardsConfigChangedEmitter.fire(this._boardsConfig));
54100
}
55101

@@ -58,14 +104,22 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
58104
}
59105

60106
protected saveState(): Promise<void> {
61-
return this.storageService.setData('boards-config', this.boardsConfig);
107+
return this.storageService.setData('latest-valid-boards-config', this.latestValidBoardsConfig);
62108
}
63109

64110
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;
68114
}
69115
}
70116

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+
71125
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type RecursiveRequired<T> = {
2+
[P in keyof T]-?: RecursiveRequired<T[P]>;
3+
};

0 commit comments

Comments
 (0)