11import { injectable , inject } from 'inversify' ;
2- import { deepClone } from '@theia/core/lib/common/objects' ;
32import { Emitter , Event } from '@theia/core/lib/common/event' ;
43import { MessageService } from '@theia/core/lib/common/message-service' ;
54import {
@@ -23,7 +22,6 @@ import { nls } from '@theia/core/lib/common/nls';
2322
2423@injectable ( )
2524export 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