Skip to content

Commit 6447191

Browse files
author
Akos Kitta
committed
[win] Implemented naive reconnecting.
For some reason, port is reported to be busy on Windows. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
1 parent e78ed85 commit 6447191

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

.vscode/launch.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@
2323
"--hostname=localhost",
2424
"--no-cluster",
2525
"--remote-debugging-port=9222",
26-
"--no-app-auto-install",
27-
"--debug-cli=true"
26+
"--no-app-auto-install"
2827
],
2928
"env": {
3029
"NODE_ENV": "development"

arduino-ide-extension/src/browser/monitor/monitor-connection.ts

+35-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { injectable, inject, postConstruct } from 'inversify';
22
import { Emitter, Event } from '@theia/core/lib/common/event';
3-
// import { ConnectionStatusService } from '@theia/core/lib/browser/connection-status-service';
43
import { MessageService } from '@theia/core/lib/common/message-service';
54
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
65
import { MonitorService, MonitorConfig, MonitorError, Status, MonitorReadEvent } from '../../common/protocol/monitor-service';
@@ -31,9 +30,6 @@ export class MonitorConnection {
3130
@inject(MessageService)
3231
protected messageService: MessageService;
3332

34-
// @inject(ConnectionStatusService)
35-
// protected readonly connectionStatusService: ConnectionStatusService;
36-
3733
@inject(FrontendApplicationStateService)
3834
protected readonly applicationState: FrontendApplicationStateService;
3935

@@ -49,6 +45,14 @@ export class MonitorConnection {
4945
*/
5046
protected readonly onReadEmitter = new Emitter<MonitorReadEvent>();
5147

48+
/**
49+
* Array for storing previous monitor errors received from the server, and based on the number of elements in this array,
50+
* we adjust the reconnection delay.
51+
* Super naive way: we wait `array.length * 1000` ms. Once we hit 10 errors, we do not try to reconnect and clean the array.
52+
*/
53+
protected monitorErrors: MonitorError[] = [];
54+
protected reconnectTimeout?: number;
55+
5256
@postConstruct()
5357
protected init(): void {
5458
// Forward the messages from the board **iff** connected.
@@ -61,33 +65,47 @@ export class MonitorConnection {
6165
let shouldReconnect = false;
6266
if (this.state) {
6367
const { code, config } = error;
68+
const { board, port } = config;
69+
const options = { timeout: 3000 };
6470
switch (code) {
6571
case MonitorError.ErrorCodes.CLIENT_CANCEL: {
6672
console.debug(`Connection was canceled by client: ${MonitorConnection.State.toString(this.state)}.`);
6773
break;
6874
}
6975
case MonitorError.ErrorCodes.DEVICE_BUSY: {
70-
const { port } = config;
71-
this.messageService.warn(`Connection failed. Serial port is busy: ${Port.toString(port)}.`);
76+
this.messageService.warn(`Connection failed. Serial port is busy: ${Port.toString(port)}.`, options);
77+
shouldReconnect = this.autoConnect;
78+
this.monitorErrors.push(error);
7279
break;
7380
}
7481
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
75-
const { port, board } = config;
76-
this.messageService.info(`Disconnected ${Board.toString(board, { useFqbn: false })} from ${Port.toString(port)}.`);
82+
this.messageService.info(`Disconnected ${Board.toString(board, { useFqbn: false })} from ${Port.toString(port)}.`, options);
7783
break;
7884
}
7985
case undefined: {
80-
const { board, port } = config;
81-
this.messageService.error(`Unexpected error. Reconnecting ${Board.toString(board)} on port ${Port.toString(port)}.`);
86+
this.messageService.error(`Unexpected error. Reconnecting ${Board.toString(board)} on port ${Port.toString(port)}.`, options);
8287
console.error(JSON.stringify(error));
83-
shouldReconnect = this.connected;
88+
shouldReconnect = this.connected && this.autoConnect;
89+
break;
8490
}
8591
}
8692
const oldState = this.state;
8793
this.state = undefined;
8894
this.onConnectionChangedEmitter.fire(this.state);
8995
if (shouldReconnect) {
90-
await this.connect(oldState.config);
96+
if (this.monitorErrors.length >= 10) {
97+
this.messageService.warn(`Failed to reconnect ${Board.toString(board, { useFqbn: false })} to the the serial-monitor after 10 consecutive attempts. The ${Port.toString(port)} serial port is busy. after 10 consecutive attempts.`);
98+
this.monitorErrors.length = 0;
99+
} else {
100+
const attempts = (this.monitorErrors.length || 1);
101+
if (this.reconnectTimeout !== undefined) {
102+
// Clear the previous timer.
103+
window.clearTimeout(this.reconnectTimeout);
104+
}
105+
const timeout = attempts * 1000;
106+
this.messageService.warn(`Reconnecting ${Board.toString(board, { useFqbn: false })} to ${Port.toString(port)} in ${attempts} seconds...`, { timeout });
107+
this.reconnectTimeout = window.setTimeout(() => this.connect(oldState.config), timeout);
108+
}
91109
}
92110
}
93111
});
@@ -138,6 +156,11 @@ export class MonitorConnection {
138156
const { boardsConfig } = this.boardsServiceClient;
139157
this.handleBoardConfigChange(boardsConfig);
140158
});
159+
} else if (oldValue && !value) {
160+
if (this.reconnectTimeout !== undefined) {
161+
window.clearTimeout(this.reconnectTimeout);
162+
this.monitorErrors.length = 0;
163+
}
141164
}
142165
}
143166

0 commit comments

Comments
 (0)