Skip to content

Commit 7d10e89

Browse files
committed
Timeout on config change to prevent serial busy
1 parent dbffcd3 commit 7d10e89

File tree

6 files changed

+123
-147
lines changed

6 files changed

+123
-147
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export class MonitorWidget extends ReactWidget {
5757
this.scrollOptions = undefined;
5858
this.toDispose.push(this.clearOutputEmitter);
5959
this.toDispose.push(
60-
Disposable.create(() => this.serialConnection.closeSerial())
60+
Disposable.create(() => this.serialConnection.closeWStoBE())
6161
);
6262
}
6363

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

8282
protected onAfterAttach(msg: Message): void {
8383
super.onAfterAttach(msg);
84-
this.serialConnection.openSerial();
84+
this.serialConnection.openWSToBE();
8585
}
8686

8787
onCloseRequest(msg: Message): void {
@@ -169,7 +169,7 @@ export class MonitorWidget extends ReactWidget {
169169
<div className="head">
170170
<div className="send">
171171
<SerialMonitorSendInput
172-
serialConfig={this.serialConnection.serialConfig}
172+
serialConnection={this.serialConnection}
173173
resolveFocus={this.onFocusResolved}
174174
onSend={this.onSend}
175175
/>

arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx

+40-11
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,66 @@
11
import * as React from 'react';
22
import { Key, KeyCode } from '@theia/core/lib/browser/keys';
33
import { Board, Port } from '../../../common/protocol/boards-service';
4-
import { SerialConfig } from '../../../common/protocol/serial-service';
54
import { isOSX } from '@theia/core/lib/common/os';
6-
import { nls } from '@theia/core/lib/common';
5+
import { DisposableCollection, nls } from '@theia/core/lib/common';
6+
import { SerialConnectionManager } from '../serial-connection-manager';
7+
import { SerialPlotter } from '../plotter/protocol';
78

89
export namespace SerialMonitorSendInput {
910
export interface Props {
10-
readonly serialConfig?: SerialConfig;
11+
readonly serialConnection: SerialConnectionManager;
1112
readonly onSend: (text: string) => void;
1213
readonly resolveFocus: (element: HTMLElement | undefined) => void;
1314
}
1415
export interface State {
1516
text: string;
17+
connected: boolean;
1618
}
1719
}
1820

1921
export class SerialMonitorSendInput extends React.Component<
2022
SerialMonitorSendInput.Props,
2123
SerialMonitorSendInput.State
2224
> {
25+
protected toDisposeBeforeUnmount = new DisposableCollection();
26+
2327
constructor(props: Readonly<SerialMonitorSendInput.Props>) {
2428
super(props);
25-
this.state = { text: '' };
29+
this.state = { text: '', connected: false };
2630
this.onChange = this.onChange.bind(this);
2731
this.onSend = this.onSend.bind(this);
2832
this.onKeyDown = this.onKeyDown.bind(this);
2933
}
3034

35+
componentDidMount(): void {
36+
this.props.serialConnection.isBESerialConnected().then((connected) => {
37+
this.setState({ connected });
38+
});
39+
40+
this.toDisposeBeforeUnmount.pushAll([
41+
this.props.serialConnection.onRead(({ messages }) => {
42+
if (
43+
messages.command ===
44+
SerialPlotter.Protocol.Command.MIDDLEWARE_CONFIG_CHANGED &&
45+
'connected' in messages.data
46+
) {
47+
this.setState({ connected: messages.data.connected });
48+
}
49+
}),
50+
]);
51+
}
52+
53+
componentWillUnmount(): void {
54+
// TODO: "Your preferred browser's local storage is almost full." Discard `content` before saving layout?
55+
this.toDisposeBeforeUnmount.dispose();
56+
}
57+
3158
render(): React.ReactNode {
3259
return (
3360
<input
3461
ref={this.setRef}
3562
type="text"
36-
className={`theia-input ${this.props.serialConfig ? '' : 'warning'}`}
63+
className={`theia-input ${this.state.connected ? '' : 'warning'}`}
3764
placeholder={this.placeholder}
3865
value={this.state.text}
3966
onChange={this.onChange}
@@ -43,8 +70,8 @@ export class SerialMonitorSendInput extends React.Component<
4370
}
4471

4572
protected get placeholder(): string {
46-
const { serialConfig } = this.props;
47-
if (!serialConfig) {
73+
const serialConfig = this.props.serialConnection.getConfig();
74+
if (!this.state.connected || !serialConfig) {
4875
return nls.localize(
4976
'arduino/serial/notConnected',
5077
'Not connected. Select a board and a port to connect automatically.'
@@ -55,10 +82,12 @@ export class SerialMonitorSendInput extends React.Component<
5582
'arduino/serial/message',
5683
"Message ({0} + Enter to send message to '{1}' on '{2}'",
5784
isOSX ? '⌘' : nls.localize('vscode/keybindingLabels/ctrlKey', 'Ctrl'),
58-
Board.toString(board, {
59-
useFqbn: false,
60-
}),
61-
Port.toString(port)
85+
board
86+
? Board.toString(board, {
87+
useFqbn: false,
88+
})
89+
: 'unknown',
90+
port ? Port.toString(port) : 'unknown'
6291
);
6392
}
6493

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

+5-68
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ export class SerialConnectionManager {
116116
}
117117

118118
/**
119-
* Set the config passing only the properties that has changed. If some has changed and the serial is open,
120-
* we try to reconnect
119+
* Updated the config in the BE passing only the properties that has changed.
120+
* BE will create a new connection if needed.
121121
*
122122
* @param newConfig the porperties of the config that has changed
123123
*/
@@ -150,10 +150,6 @@ export class SerialConnectionManager {
150150
return this.wsPort;
151151
}
152152

153-
isWebSocketConnected(): boolean {
154-
return !!this.webSocket?.url;
155-
}
156-
157153
protected handleWebSocketChanged(wsPort: number): void {
158154
this.wsPort = wsPort;
159155
}
@@ -168,7 +164,7 @@ export class SerialConnectionManager {
168164
return await this.serialService.isSerialPortOpen();
169165
}
170166

171-
openSerial(): void {
167+
openWSToBE(): void {
172168
if (!isSerialConfig(this.config)) {
173169
this.messageService.error(
174170
`Please select a board and a port to open the serial connection.`
@@ -189,7 +185,7 @@ export class SerialConnectionManager {
189185
}
190186
}
191187

192-
closeSerial(): void {
188+
closeWStoBE(): void {
193189
if (this.webSocket) {
194190
try {
195191
this.webSocket.close();
@@ -297,28 +293,6 @@ export class SerialConnectionManager {
297293
}
298294
}
299295

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-
322296
async reconnectAfterUpload(): Promise<void> {
323297
try {
324298
if (isSerialConfig(this.config)) {
@@ -339,31 +313,6 @@ export class SerialConnectionManager {
339313
}
340314
}
341315

342-
async disconnectSerialPort(): Promise<Status> {
343-
if (!(await this.serialService.isSerialPortOpen())) {
344-
return Status.OK;
345-
}
346-
347-
console.log('>>> Disposing existing serial connection...');
348-
const status = await this.serialService.disconnect();
349-
if (Status.isOK(status)) {
350-
console.log(
351-
`<<< Disposed serial connection. Was: ${Serial.Config.toString(
352-
this.config
353-
)}`
354-
);
355-
this.wsPort = undefined;
356-
} else {
357-
console.warn(
358-
`<<< Could not dispose serial connection. Activate connection: ${Serial.Config.toString(
359-
this.config
360-
)}`
361-
);
362-
}
363-
364-
return status;
365-
}
366-
367316
/**
368317
* Sends the data to the connected serial port.
369318
* The desired EOL is appended to `data`, you do not have to add it.
@@ -384,7 +333,7 @@ export class SerialConnectionManager {
384333
return this.onConnectionChangedEmitter.event;
385334
}
386335

387-
get onRead(): Event<{ messages: string[] }> {
336+
get onRead(): Event<{ messages: any }> {
388337
return this.onReadEmitter.event;
389338
}
390339

@@ -399,18 +348,6 @@ export class SerialConnectionManager {
399348
}
400349

401350
export namespace Serial {
402-
export enum Type {
403-
Monitor = 'Monitor',
404-
Plotter = 'Plotter',
405-
}
406-
407-
/**
408-
* The state represents which types of connections are needed by the client, and it should match whether the Serial Monitor
409-
* or the Serial Plotter are open or not in the GUI. It's an array cause it's possible to have both, none or only one of
410-
* them open
411-
*/
412-
export type State = Serial.Type[];
413-
414351
export namespace Config {
415352
export function toString(config: Partial<SerialConfig>): string {
416353
if (!isSerialConfig(config)) return '';

0 commit comments

Comments
 (0)