Skip to content

Commit 09c4709

Browse files
fstasiAlberto Iannaccone
authored and
Alberto Iannaccone
committed
handle serial connect in the BE
1 parent 04f67b9 commit 09c4709

File tree

12 files changed

+543
-542
lines changed

12 files changed

+543
-542
lines changed

arduino-ide-extension/src/browser/contributions/burn-bootloader.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export class BurnBootloader extends SketchContribution {
4848
}
4949

5050
async burnBootloader(): Promise<void> {
51-
await this.serialConnection.disconnect();
5251
try {
5352
const { boardsConfig } = this.boardsServiceClientImpl;
5453
const port = boardsConfig.selectedPort;
@@ -81,9 +80,7 @@ export class BurnBootloader extends SketchContribution {
8180
} catch (e) {
8281
this.messageService.error(e.toString());
8382
} finally {
84-
if (this.serialConnection.widgetsAttached()) {
85-
await this.serialConnection.connect();
86-
}
83+
await this.serialConnection.reconnectAfterUpload();
8784
}
8885
}
8986
}

arduino-ide-extension/src/browser/contributions/upload-sketch.ts

+2-22
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export class UploadSketch extends SketchContribution {
210210
if (!sketch) {
211211
return;
212212
}
213-
await this.serialConnection.disconnect();
213+
214214
try {
215215
const { boardsConfig } = this.boardsServiceClientImpl;
216216
const [fqbn, { selectedProgrammer }, verify, verbose, sourceOverride] =
@@ -282,27 +282,7 @@ export class UploadSketch extends SketchContribution {
282282
this.uploadInProgress = false;
283283
this.onDidChangeEmitter.fire();
284284

285-
if (
286-
this.serialConnection.widgetsAttached() &&
287-
this.serialConnection.serialConfig
288-
) {
289-
const { board, port } = this.serialConnection.serialConfig;
290-
try {
291-
await this.boardsServiceClientImpl.waitUntilAvailable(
292-
Object.assign(board, { port }),
293-
10_000
294-
);
295-
await this.serialConnection.connect();
296-
} catch (waitError) {
297-
this.messageService.error(
298-
nls.localize(
299-
'arduino/sketch/couldNotConnectToSerial',
300-
'Could not reconnect to serial port. {0}',
301-
waitError.toString()
302-
)
303-
);
304-
}
305-
}
285+
setTimeout(() => this.serialConnection.reconnectAfterUpload(), 5000);
306286
}
307287
}
308288
}

arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { SerialConfig } from '../../../common/protocol/serial-service';
1313
import { ArduinoSelect } from '../../widgets/arduino-select';
1414
import { SerialModel } from '../serial-model';
15-
import { Serial, SerialConnectionManager } from '../serial-connection-manager';
15+
import { SerialConnectionManager } from '../serial-connection-manager';
1616
import { SerialMonitorSendInput } from './serial-monitor-send-input';
1717
import { SerialMonitorOutput } from './serial-monitor-send-output';
1818
import { BoardsServiceProvider } from '../../boards/boards-service-provider';
@@ -57,9 +57,7 @@ export class MonitorWidget extends ReactWidget {
5757
this.scrollOptions = undefined;
5858
this.toDispose.push(this.clearOutputEmitter);
5959
this.toDispose.push(
60-
Disposable.create(() =>
61-
this.serialConnection.closeSerial(Serial.Type.Monitor)
62-
)
60+
Disposable.create(() => this.serialConnection.closeSerial())
6361
);
6462
}
6563

@@ -83,7 +81,7 @@ export class MonitorWidget extends ReactWidget {
8381

8482
protected onAfterAttach(msg: Message): void {
8583
super.onAfterAttach(msg);
86-
this.serialConnection.openSerial(Serial.Type.Monitor);
84+
this.serialConnection.openSerial();
8785
}
8886

8987
onCloseRequest(msg: Message): void {

arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { ArduinoMenus } from '../../menu/arduino-menus';
1111
import { Contribution } from '../../contributions/contribution';
1212
import { Endpoint, FrontendApplication } from '@theia/core/lib/browser';
1313
import { ipcRenderer } from '@theia/core/shared/electron';
14-
import { SerialConfig, Status } from '../../../common/protocol';
15-
import { Serial, SerialConnectionManager } from '../serial-connection-manager';
14+
import { SerialConfig } from '../../../common/protocol';
15+
import { SerialConnectionManager } from '../serial-connection-manager';
1616
import { SerialPlotter } from './protocol';
1717
import { BoardsServiceProvider } from '../../boards/boards-service-provider';
1818
const queryString = require('query-string');
@@ -51,10 +51,8 @@ export class PlotterFrontendContribution extends Contribution {
5151
ipcRenderer.on('CLOSE_CHILD_WINDOW', async () => {
5252
if (!!this.window) {
5353
this.window = null;
54-
await this.serialConnection.closeSerial(Serial.Type.Plotter);
5554
}
5655
});
57-
5856
return super.onStart(app);
5957
}
6058

@@ -77,12 +75,10 @@ export class PlotterFrontendContribution extends Contribution {
7775
this.window.focus();
7876
return;
7977
}
80-
const status = await this.serialConnection.openSerial(Serial.Type.Plotter);
8178
const wsPort = this.serialConnection.getWsPort();
82-
if (Status.isOK(status) && wsPort) {
79+
if (wsPort) {
8380
this.open(wsPort);
8481
} else {
85-
this.serialConnection.closeSerial(Serial.Type.Plotter);
8682
this.messageService.error(`Couldn't open serial plotter`);
8783
}
8884
}

arduino-ide-extension/src/browser/serial/serial-connection-manager.ts

+69-121
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { injectable, inject } from 'inversify';
2-
import { deepClone } from '@theia/core/lib/common/objects';
32
import { Emitter, Event } from '@theia/core/lib/common/event';
43
import { MessageService } from '@theia/core/lib/common/message-service';
54
import {
@@ -23,7 +22,6 @@ import { nls } from '@theia/core/lib/common/nls';
2322

2423
@injectable()
2524
export class SerialConnectionManager {
26-
protected _state: Serial.State = [];
2725
protected config: Partial<SerialConfig> = {
2826
board: undefined,
2927
port: undefined,
@@ -61,7 +59,9 @@ export class SerialConnectionManager {
6159
protected readonly boardsServiceProvider: BoardsServiceProvider,
6260
@inject(MessageService) protected messageService: MessageService,
6361
@inject(ThemeService) protected readonly themeService: ThemeService,
64-
@inject(CoreService) protected readonly core: CoreService
62+
@inject(CoreService) protected readonly core: CoreService,
63+
@inject(BoardsServiceProvider)
64+
protected readonly boardsServiceClientImpl: BoardsServiceProvider
6565
) {
6666
this.serialServiceClient.onWebSocketChanged(
6767
this.handleWebSocketChanged.bind(this)
@@ -129,17 +129,16 @@ export class SerialConnectionManager {
129129
this.config = { ...this.config, [key]: newConfig[key] };
130130
}
131131
});
132-
if (
133-
configHasChanged &&
134-
this.widgetsAttached() &&
135-
!(await this.core.isUploading())
136-
) {
132+
133+
if (configHasChanged) {
137134
this.serialService.updateWsConfigParam({
138135
currentBaudrate: this.config.baudRate,
139136
serialPort: this.config.port?.address,
140137
});
141-
await this.disconnect();
142-
await this.connect();
138+
139+
if (isSerialConfig(this.config)) {
140+
this.serialService.setSerialConfig(this.config);
141+
}
143142
}
144143
}
145144

@@ -159,61 +158,6 @@ export class SerialConnectionManager {
159158
this.wsPort = wsPort;
160159
}
161160

162-
/**
163-
* When the serial is open and the frontend is connected to the serial, we create the websocket here
164-
*/
165-
protected createWsConnection(): boolean {
166-
if (this.wsPort) {
167-
try {
168-
this.webSocket = new WebSocket(`ws://localhost:${this.wsPort}`);
169-
this.webSocket.onmessage = (res) => {
170-
const messages = JSON.parse(res.data);
171-
this.onReadEmitter.fire({ messages });
172-
};
173-
return true;
174-
} catch {
175-
return false;
176-
}
177-
}
178-
return false;
179-
}
180-
181-
/**
182-
* Sets the types of connections needed by the client.
183-
*
184-
* @param newState The array containing the list of desired connections.
185-
* If the previuos state was empty and 'newState' is not, it tries to reconnect to the serial service
186-
* If the provios state was NOT empty and now it is, it disconnects to the serial service
187-
* @returns The status of the operation
188-
*/
189-
protected async setState(newState: Serial.State): Promise<Status> {
190-
const oldState = deepClone(this._state);
191-
let status = Status.OK;
192-
193-
if (this.widgetsAttached(oldState) && !this.widgetsAttached(newState)) {
194-
status = await this.disconnect();
195-
} else if (
196-
!this.widgetsAttached(oldState) &&
197-
this.widgetsAttached(newState)
198-
) {
199-
if (await this.core.isUploading()) {
200-
this.messageService.error(`Cannot open serial port when uploading`);
201-
return Status.NOT_CONNECTED;
202-
}
203-
status = await this.connect();
204-
}
205-
this._state = newState;
206-
return status;
207-
}
208-
209-
protected get state(): Serial.State {
210-
return this._state;
211-
}
212-
213-
widgetsAttached(state?: Serial.State): boolean {
214-
return (state ? state : this._state).length > 0;
215-
}
216-
217161
get serialConfig(): SerialConfig | undefined {
218162
return isSerialConfig(this.config)
219163
? (this.config as SerialConfig)
@@ -224,52 +168,36 @@ export class SerialConnectionManager {
224168
return await this.serialService.isSerialPortOpen();
225169
}
226170

227-
/**
228-
* Called when a client opens the serial from the GUI
229-
*
230-
* @param type could be either 'Monitor' or 'Plotter'. If it's 'Monitor' we also connect to the websocket and
231-
* listen to the message events
232-
* @returns the status of the operation
233-
*/
234-
async openSerial(type: Serial.Type): Promise<Status> {
171+
openSerial(): void {
235172
if (!isSerialConfig(this.config)) {
236173
this.messageService.error(
237174
`Please select a board and a port to open the serial connection.`
238175
);
239-
return Status.NOT_CONNECTED;
176+
return;
177+
}
178+
179+
if (!this.webSocket && this.wsPort) {
180+
try {
181+
this.webSocket = new WebSocket(`ws://localhost:${this.wsPort}`);
182+
this.webSocket.onmessage = (res) => {
183+
const messages = JSON.parse(res.data);
184+
this.onReadEmitter.fire({ messages });
185+
};
186+
} catch {
187+
this.messageService.error(`Unable to connect to websocket`);
188+
}
240189
}
241-
if (this.state.includes(type)) return Status.OK;
242-
const newState = deepClone(this.state);
243-
newState.push(type);
244-
const status = await this.setState(newState);
245-
if (Status.isOK(status) && type === Serial.Type.Monitor)
246-
this.createWsConnection();
247-
return status;
248190
}
249191

250-
/**
251-
* Called when a client closes the serial from the GUI
252-
*
253-
* @param type could be either 'Monitor' or 'Plotter'. If it's 'Monitor' we close the websocket connection
254-
* @returns the status of the operation
255-
*/
256-
async closeSerial(type: Serial.Type): Promise<Status> {
257-
const index = this.state.indexOf(type);
258-
let status = Status.OK;
259-
if (index >= 0) {
260-
const newState = deepClone(this.state);
261-
newState.splice(index, 1);
262-
status = await this.setState(newState);
263-
if (
264-
Status.isOK(status) &&
265-
type === Serial.Type.Monitor &&
266-
this.webSocket
267-
) {
192+
closeSerial(): void {
193+
if (this.webSocket) {
194+
try {
268195
this.webSocket.close();
269196
this.webSocket = undefined;
197+
} catch {
198+
this.messageService.error(`Unable to close websocket`);
270199
}
271200
}
272-
return status;
273201
}
274202

275203
/**
@@ -330,7 +258,7 @@ export class SerialConnectionManager {
330258
}
331259
}
332260

333-
if (this.widgetsAttached()) {
261+
if ((await this.serialService.clientsAttached()) > 0) {
334262
if (this.serialErrors.length >= 10) {
335263
this.messageService.warn(
336264
nls.localize(
@@ -362,36 +290,56 @@ export class SerialConnectionManager {
362290
)
363291
);
364292
this.reconnectTimeout = window.setTimeout(
365-
() => this.connect(),
293+
() => this.reconnectAfterUpload(),
366294
timeout
367295
);
368296
}
369297
}
370298
}
371299

372-
async connect(): Promise<Status> {
373-
if (await this.serialService.isSerialPortOpen())
374-
return Status.ALREADY_CONNECTED;
375-
if (!isSerialConfig(this.config)) return Status.NOT_CONNECTED;
376-
377-
console.info(
378-
`>>> Creating serial connection for ${Board.toString(
379-
this.config.board
380-
)} on port ${Port.toString(this.config.port)}...`
381-
);
382-
const connectStatus = await this.serialService.connect(this.config);
383-
if (Status.isOK(connectStatus)) {
384-
console.info(
385-
`<<< Serial connection created for ${Board.toString(this.config.board, {
386-
useFqbn: false,
387-
})} on port ${Port.toString(this.config.port)}.`
300+
// async connect(): Promise<Status> {
301+
// if (await this.serialService.isSerialPortOpen())
302+
// return Status.ALREADY_CONNECTED;
303+
// if (!isSerialConfig(this.config)) return Status.NOT_CONNECTED;
304+
305+
// console.info(
306+
// `>>> Creating serial connection for ${Board.toString(
307+
// this.config.board
308+
// )} on port ${Port.toString(this.config.port)}...`
309+
// );
310+
// const connectStatus = await this.serialService.connect(this.config);
311+
// if (Status.isOK(connectStatus)) {
312+
// console.info(
313+
// `<<< Serial connection created for ${Board.toString(this.config.board, {
314+
// useFqbn: false,
315+
// })} on port ${Port.toString(this.config.port)}.`
316+
// );
317+
// }
318+
319+
// return Status.isOK(connectStatus);
320+
// }
321+
322+
async reconnectAfterUpload(): Promise<void> {
323+
try {
324+
if (isSerialConfig(this.config)) {
325+
await this.boardsServiceClientImpl.waitUntilAvailable(
326+
Object.assign(this.config.board, { port: this.config.port }),
327+
10_000
328+
);
329+
this.serialService.connectSerialIfRequired();
330+
}
331+
} catch (waitError) {
332+
this.messageService.error(
333+
nls.localize(
334+
'arduino/sketch/couldNotConnectToSerial',
335+
'Could not reconnect to serial port. {0}',
336+
waitError.toString()
337+
)
388338
);
389339
}
390-
391-
return Status.isOK(connectStatus);
392340
}
393341

394-
async disconnect(): Promise<Status> {
342+
async disconnectSerialPort(): Promise<Status> {
395343
if (!(await this.serialService.isSerialPortOpen())) {
396344
return Status.OK;
397345
}

0 commit comments

Comments
 (0)