mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-08 11:56:36 +00:00
slightly better reconnecting experience.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
a4e5e65286
commit
c7242ca34f
@ -107,6 +107,20 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
|
|||||||
return this._boardsConfig;
|
return this._boardsConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `true` if the `config.selectedBoard` is defined; hence can compile against the board. Otherwise, `false`.
|
||||||
|
*/
|
||||||
|
canVerify(config: BoardsConfig.Config | undefined = this.boardsConfig): config is BoardsConfig.Config & { selectedBoard: Board } {
|
||||||
|
return !!config && !!config.selectedBoard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `true` if the `canVerify` and the `config.selectedPort` is also set with FQBN, hence can upload to board. Otherwise, `false`.
|
||||||
|
*/
|
||||||
|
canUploadTo(config: BoardsConfig.Config | undefined = this.boardsConfig): config is RecursiveRequired<BoardsConfig.Config> {
|
||||||
|
return this.canVerify(config) && !!config.selectedPort && !!config.selectedBoard.fqbn;
|
||||||
|
}
|
||||||
|
|
||||||
protected saveState(): Promise<void> {
|
protected saveState(): Promise<void> {
|
||||||
return this.storageService.setData('latest-valid-boards-config', this.latestValidBoardsConfig);
|
return this.storageService.setData('latest-valid-boards-config', this.latestValidBoardsConfig);
|
||||||
}
|
}
|
||||||
@ -118,12 +132,4 @@ export class BoardsServiceClientImpl implements BoardsServiceClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected canVerify(config: BoardsConfig.Config | undefined): config is BoardsConfig.Config & { selectedBoard: Board } {
|
|
||||||
return !!config && !!config.selectedBoard;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected canUploadTo(config: BoardsConfig.Config | undefined): config is RecursiveRequired<BoardsConfig.Config> {
|
|
||||||
return this.canVerify(config) && !!config.selectedPort && !!config.selectedBoard.fqbn;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ export class MonitorConnection {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
|
case MonitorError.ErrorCodes.DEVICE_NOT_CONFIGURED: {
|
||||||
const { port } = config;
|
const { port, board } = config;
|
||||||
this.messageService.info(`Disconnected from ${Port.toString(port)}.`);
|
this.messageService.info(`Disconnected ${Board.toString(board, { useFqbn: false })} from ${Port.toString(port)}.`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case undefined: {
|
case undefined: {
|
||||||
@ -77,19 +77,22 @@ export class MonitorConnection {
|
|||||||
|
|
||||||
async connect(config: MonitorConfig): Promise<Status> {
|
async connect(config: MonitorConfig): Promise<Status> {
|
||||||
if (this.state) {
|
if (this.state) {
|
||||||
throw new Error(`Already connected to ${MonitorConnection.State.toString(this.state)}.`);
|
const disconnectStatus = await this.disconnect();
|
||||||
|
if (!Status.isOK(disconnectStatus)) {
|
||||||
|
return disconnectStatus;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const status = await this.monitorService.connect(config);
|
const connectStatus = await this.monitorService.connect(config);
|
||||||
if (Status.isOK(status)) {
|
if (Status.isOK(connectStatus)) {
|
||||||
this.state = { config };
|
this.state = { config };
|
||||||
this.onConnectionChangedEmitter.fire(true);
|
this.onConnectionChangedEmitter.fire(true);
|
||||||
}
|
}
|
||||||
return Status.isOK(status);
|
return Status.isOK(connectStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect(): Promise<Status> {
|
async disconnect(): Promise<Status> {
|
||||||
if (!this.state) {
|
if (!this.state) {
|
||||||
throw new Error('Not connected. Nothing to disconnect.');
|
return Status.OK;
|
||||||
}
|
}
|
||||||
console.log('>>> Disposing existing monitor connection before establishing a new one...');
|
console.log('>>> Disposing existing monitor connection before establishing a new one...');
|
||||||
const status = await this.monitorService.disconnect();
|
const status = await this.monitorService.disconnect();
|
||||||
|
@ -9,7 +9,7 @@ import { MessageService } from '@theia/core/lib/common/message-service';
|
|||||||
import { ReactWidget, Message, Widget } from '@theia/core/lib/browser';
|
import { ReactWidget, Message, Widget } from '@theia/core/lib/browser';
|
||||||
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
|
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
|
||||||
import { MonitorConfig, MonitorService } from '../../common/protocol/monitor-service';
|
import { MonitorConfig, MonitorService } from '../../common/protocol/monitor-service';
|
||||||
import { AttachedSerialBoard, BoardsService } from '../../common/protocol/boards-service';
|
import { AttachedSerialBoard, BoardsService, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||||
import { BoardsConfig } from '../boards/boards-config';
|
import { BoardsConfig } from '../boards/boards-config';
|
||||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||||
import { MonitorModel } from './monitor-model';
|
import { MonitorModel } from './monitor-model';
|
||||||
@ -171,16 +171,24 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.boardsServiceClient.onBoardsConfigChanged(config => {
|
this.boardsServiceClient.onBoardsConfigChanged(config => {
|
||||||
const { selectedBoard, selectedPort } = config;
|
if (this.boardsServiceClient.canUploadTo(config)) {
|
||||||
if (selectedBoard && selectedPort) {
|
|
||||||
this.boardsService.getAttachedBoards().then(({ boards }) => {
|
this.boardsService.getAttachedBoards().then(({ boards }) => {
|
||||||
if (boards.filter(AttachedSerialBoard.is).some(board => BoardsConfig.Config.sameAs(config, board))) {
|
if (boards.filter(AttachedSerialBoard.is).some(board => BoardsConfig.Config.sameAs(config, board))) {
|
||||||
this.clearConsole();
|
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})]);
|
}),
|
||||||
|
this.boardsServiceClient.onBoardsChanged(event => {
|
||||||
|
const { attached } = AttachedBoardsChangeEvent.diff(event);
|
||||||
|
if (!this.connection.connected && this.boardsServiceClient.canUploadTo()) {
|
||||||
|
const { boardsConfig } = this.boardsServiceClient;
|
||||||
|
if (attached.boards.filter(AttachedSerialBoard.is).some(board => BoardsConfig.Config.sameAs(boardsConfig, board))) {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]);
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +222,7 @@ export class MonitorWidget extends ReactWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async connect(): Promise<void> {
|
protected async connect(): Promise<void> {
|
||||||
|
this.clearConsole();
|
||||||
const config = await this.getConnectionConfig();
|
const config = await this.getConnectionConfig();
|
||||||
if (config) {
|
if (config) {
|
||||||
this.connection.connect(config);
|
this.connection.connect(config);
|
||||||
|
@ -13,11 +13,11 @@ export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
|||||||
protected readonly outputContribution: OutputContribution;
|
protected readonly outputContribution: OutputContribution;
|
||||||
|
|
||||||
onNewOutput(tool: string, chunk: string): void {
|
onNewOutput(tool: string, chunk: string): void {
|
||||||
this.outputContribution.openView({ reveal: true }).then(() => {
|
this.outputContribution.openView({ activate: true }).then(() => {
|
||||||
const channel = this.outputChannelManager.getChannel(`Arduino: ${tool}`);
|
const channel = this.outputChannelManager.getChannel(`Arduino: ${tool}`);
|
||||||
channel.setVisibility(true);
|
channel.setVisibility(true);
|
||||||
channel.append(chunk);
|
channel.append(chunk);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -214,8 +214,8 @@ export namespace Board {
|
|||||||
return !!board.fqbn;
|
return !!board.fqbn;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toString(board: Board): string {
|
export function toString(board: Board, options: { useFqbn: boolean } = { useFqbn: true }): string {
|
||||||
const fqbn = board.fqbn ? ` [${board.fqbn}]` : '';
|
const fqbn = options && options.useFqbn && board.fqbn ? ` [${board.fqbn}]` : '';
|
||||||
return `${board.name}${fqbn}`;
|
return `${board.name}${fqbn}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
protected readonly monitorClientProvider: MonitorClientProvider;
|
protected readonly monitorClientProvider: MonitorClientProvider;
|
||||||
|
|
||||||
protected client?: MonitorServiceClient;
|
protected client?: MonitorServiceClient;
|
||||||
protected connection?: ClientDuplexStream<StreamingOpenReq, StreamingOpenResp>;
|
protected connection?: { duplex: ClientDuplexStream<StreamingOpenReq, StreamingOpenResp>, config: MonitorConfig };
|
||||||
|
|
||||||
setClient(client: MonitorServiceClient | undefined): void {
|
setClient(client: MonitorServiceClient | undefined): void {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
@ -66,20 +66,23 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
return Status.ALREADY_CONNECTED;
|
return Status.ALREADY_CONNECTED;
|
||||||
}
|
}
|
||||||
const client = await this.monitorClientProvider.client;
|
const client = await this.monitorClientProvider.client;
|
||||||
this.connection = client.streamingOpen();
|
const duplex = client.streamingOpen();
|
||||||
this.connection.on('error', ((error: Error) => {
|
this.connection = { duplex, config };
|
||||||
|
|
||||||
|
duplex.on('error', ((error: Error) => {
|
||||||
const monitorError = ErrorWithCode.toMonitorError(error, config);
|
const monitorError = ErrorWithCode.toMonitorError(error, config);
|
||||||
if (monitorError.code === undefined) {
|
this.disconnect().then(() => {
|
||||||
this.logger.error(error);
|
|
||||||
}
|
|
||||||
((monitorError.code === undefined ? this.disconnect() : Promise.resolve()) as Promise<any>).then(() => {
|
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
this.client.notifyError(monitorError);
|
this.client.notifyError(monitorError);
|
||||||
}
|
}
|
||||||
})
|
if (monitorError.code === undefined) {
|
||||||
|
// Log the original, unexpected error.
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
|
|
||||||
this.connection.on('data', ((resp: StreamingOpenResp) => {
|
duplex.on('data', ((resp: StreamingOpenResp) => {
|
||||||
if (this.client) {
|
if (this.client) {
|
||||||
const raw = resp.getData();
|
const raw = resp.getData();
|
||||||
const data = typeof raw === 'string' ? raw : new TextDecoder('utf8').decode(raw);
|
const data = typeof raw === 'string' ? raw : new TextDecoder('utf8').decode(raw);
|
||||||
@ -99,21 +102,25 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
|
|
||||||
return new Promise<Status>(resolve => {
|
return new Promise<Status>(resolve => {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
this.connection.write(req, () => {
|
this.connection.duplex.write(req, () => {
|
||||||
this.logger.info(`<<< Serial monitor connection created for ${Board.toString(config.board)} on port ${Port.toString(config.port)}.`);
|
this.logger.info(`<<< Serial monitor connection created for ${Board.toString(config.board, { useFqbn: false })} on port ${Port.toString(config.port)}.`);
|
||||||
resolve(Status.OK);
|
resolve(Status.OK);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve(Status.NOT_CONNECTED);
|
this.disconnect().then(() => resolve(Status.NOT_CONNECTED));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect(): Promise<Status> {
|
async disconnect(): Promise<Status> {
|
||||||
|
this.logger.info(`>>> Disposing monitor connection...`);
|
||||||
if (!this.connection) {
|
if (!this.connection) {
|
||||||
|
this.logger.warn(`<<< Not connected. Nothing to dispose.`);
|
||||||
return Status.NOT_CONNECTED;
|
return Status.NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
this.connection.cancel();
|
const { duplex, config } = this.connection;
|
||||||
|
duplex.cancel();
|
||||||
|
this.logger.info(`<<< Disposed monitor connection for ${Board.toString(config.board, { useFqbn: false })} on port ${Port.toString(config.port)}.`);
|
||||||
this.connection = undefined;
|
this.connection = undefined;
|
||||||
return Status.OK;
|
return Status.OK;
|
||||||
}
|
}
|
||||||
@ -126,12 +133,12 @@ export class MonitorServiceImpl implements MonitorService {
|
|||||||
req.setData(new TextEncoder().encode(data));
|
req.setData(new TextEncoder().encode(data));
|
||||||
return new Promise<Status>(resolve => {
|
return new Promise<Status>(resolve => {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
this.connection.write(req, () => {
|
this.connection.duplex.write(req, () => {
|
||||||
resolve(Status.OK);
|
resolve(Status.OK);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve(Status.NOT_CONNECTED);
|
this.disconnect().then(() => resolve(Status.NOT_CONNECTED));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user