ATL-469: Fixed various serial-monitor issues.

- Fixed a monitor reconnecting issue after upload.
 - Serial monitor connection was not disposed when the widget was closed
from the toolbar with the magnifier (🔍) icon. It worked only iff the
user closed the view with the `X`.
 - This commit also fixes a warning that was related to the incorrect focus
handling of the widget.
 - Switched to `board list -w` instead of polling.
 - Added a singleton for the board discovery to spare the CPU.
 - Fixed DI scopes on the backend. Each frontend gets its own service.
 - Switched to the `20201112` nightly CLI.
 - Fixed the Monitor view's image when the view is on the side-bar.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta
2020-10-21 17:17:40 +02:00
committed by Akos Kitta
parent 01e42dafde
commit 138afbf7fd
16 changed files with 1772 additions and 217 deletions

View File

@@ -265,6 +265,29 @@ export class BoardsServiceProvider implements FrontendApplicationContribution {
return this._availableBoards;
}
async waitUntilAvailable(what: Board & { port: Port }, timeout?: number): Promise<void> {
const find = (needle: Board & { port: Port }, haystack: AvailableBoard[]) =>
haystack.find(board => Board.equals(needle, board) && Port.equals(needle.port, board.port));
const timeoutTask = !!timeout && timeout > 0
? new Promise<void>((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${timeout} ms.`)), timeout))
: new Promise<void>(() => { /* never */ });
const waitUntilTask = new Promise<void>(resolve => {
let candidate = find(what, this.availableBoards);
if (candidate) {
resolve();
return;
}
const disposable = this.onAvailableBoardsChanged(availableBoards => {
candidate = find(what, availableBoards);
if (candidate) {
disposable.dispose();
resolve();
}
});
});
return await Promise.race([waitUntilTask, timeoutTask]);
}
protected async reconcileAvailableBoards(): Promise<void> {
const attachedBoards = this._attachedBoards;
const availablePorts = this._availablePorts;

View File

@@ -77,9 +77,14 @@ export class UploadSketch extends SketchContribution {
if (!uri) {
return;
}
let shouldAutoConnect = false;
const monitorConfig = this.monitorConnection.monitorConfig;
if (monitorConfig) {
await this.monitorConnection.disconnect();
if (this.monitorConnection.autoConnect) {
shouldAutoConnect = true;
}
this.monitorConnection.autoConnect = false;
}
try {
const { boardsConfig } = this.boardsServiceClientImpl;
@@ -122,7 +127,18 @@ export class UploadSketch extends SketchContribution {
this.messageService.error(e.toString());
} finally {
if (monitorConfig) {
await this.monitorConnection.connect(monitorConfig);
const { board, port } = monitorConfig;
try {
await this.boardsServiceClientImpl.waitUntilAvailable(Object.assign(board, { port }), 10_000);
if (shouldAutoConnect) {
// Enabling auto-connect will trigger a connect.
this.monitorConnection.autoConnect = true;
} else {
await this.monitorConnection.connect(monitorConfig);
}
} catch (waitError) {
this.messageService.error(`Could not reconnect to serial monitor. ${waitError.toString()}`);
}
}
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="24" height="24" viewBox="0, 0, 24, 24">
<g>
<path d="M16.2 8.1c0-4.5-3.6-8.1-8.1-8.1S0 3.6 0 8.1s3.6 8.1 8.1 8.1c1.9 0 3.7-.7 5.1-1.8l5.6 5.6 1.4-1.4-5.7-5.6c1.1-1.4 1.7-3.1 1.7-4.9zm-14.4 0c0-3.5 2.8-6.3 6.3-6.3s6.3 2.8 6.3 6.3-2.8 6.3-6.3 6.3c-3.5.1-6.3-2.8-6.3-6.3z" />
<rect x="7.1" y="7.1" width="2" height="2" />
<rect x="17.2" y="7.1" width="2" height="2" />
<rect x="20.3" y="7.1" width="2" height="2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 711 B

View File

@@ -5,7 +5,7 @@ import { OptionsType } from 'react-select/src/types';
import { isOSX } from '@theia/core/lib/common/os';
import { Event, Emitter } from '@theia/core/lib/common/event';
import { Key, KeyCode } from '@theia/core/lib/browser/keys';
import { DisposableCollection } from '@theia/core/lib/common/disposable'
import { DisposableCollection, Disposable } from '@theia/core/lib/common/disposable'
import { ReactWidget, Message, Widget, MessageLoop } from '@theia/core/lib/browser/widgets';
import { Board, Port } from '../../common/protocol/boards-service';
import { MonitorConfig } from '../../common/protocol/monitor-service';
@@ -45,10 +45,16 @@ export class MonitorWidget extends ReactWidget {
super();
this.id = MonitorWidget.ID;
this.title.label = 'Serial Monitor';
this.title.iconClass = 'arduino-serial-monitor-tab-icon';
this.title.iconClass = 'monitor-tab-icon';
this.title.closable = true;
this.scrollOptions = undefined;
this.toDispose.push(this.clearOutputEmitter);
this.toDispose.push(Disposable.create(() => {
this.monitorConnection.autoConnect = false;
if (this.monitorConnection.connected) {
this.monitorConnection.disconnect();
}
}));
}
@postConstruct()
@@ -73,10 +79,6 @@ export class MonitorWidget extends ReactWidget {
onCloseRequest(msg: Message): void {
this.closing = true;
this.monitorConnection.autoConnect = false;
if (this.monitorConnection.connected) {
this.monitorConnection.disconnect();
}
super.onCloseRequest(msg);
}
@@ -100,6 +102,9 @@ export class MonitorWidget extends ReactWidget {
}
protected onFocusResolved = (element: HTMLElement | undefined) => {
if (this.closing || !this.isAttached) {
return;
}
this.focusNode = element;
requestAnimationFrame(() => MessageLoop.sendMessage(this, Widget.Msg.ActivateRequest));
}

View File

@@ -1,8 +1,6 @@
.p-TabBar.theia-app-centers .p-TabBar-tabIcon.arduino-serial-monitor-tab-icon {
background: url(../icons/buttons.svg);
background-size: 800%;
background-position-y: 41px;
background-position-x: 19px;
.monitor-tab-icon {
-webkit-mask: url('../icons/monitor-tab-icon.svg');
mask: url('../icons/monitor-tab-icon.svg');
}
.serial-monitor {