11const baudrates = document . getElementById ( "baudrates" ) as HTMLSelectElement ;
22const consoleBaudrates = document . getElementById ( "consoleBaudrates" ) as HTMLSelectElement ;
3+ const reconnectDelay = document . getElementById ( "reconnectDelay" ) as HTMLInputElement ;
4+ const maxRetriesInput = document . getElementById ( "maxRetries" ) as HTMLInputElement ;
35const connectButton = document . getElementById ( "connectButton" ) as HTMLButtonElement ;
46const traceButton = document . getElementById ( "copyTraceButton" ) as HTMLButtonElement ;
57const disconnectButton = document . getElementById ( "disconnectButton" ) as HTMLButtonElement ;
@@ -37,6 +39,7 @@ const term = new Terminal({ cols: 120, rows: 40 });
3739term . open ( terminal ) ;
3840
3941let device = null ;
42+ let deviceInfo = null ;
4043let transport : Transport ;
4144let chip : string = null ;
4245let esploader : ESPLoader ;
@@ -88,6 +91,7 @@ connectButton.onclick = async () => {
8891 try {
8992 if ( device === null ) {
9093 device = await serialLib . requestPort ( { } ) ;
94+ deviceInfo = device . getInfo ( ) ;
9195 transport = new Transport ( device , true ) ;
9296 }
9397 const flashOptions = {
@@ -209,6 +213,7 @@ function removeRow(row: HTMLTableRowElement) {
209213 */
210214function cleanUp ( ) {
211215 device = null ;
216+ deviceInfo = null ;
212217 transport = null ;
213218 chip = null ;
214219}
@@ -232,11 +237,71 @@ disconnectButton.onclick = async () => {
232237} ;
233238
234239let isConsoleClosed = false ;
240+ let isReconnecting = false ;
241+
242+ const sleep = async ( ms : number ) => {
243+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
244+ } ;
245+
235246consoleStartButton . onclick = async ( ) => {
236247 if ( device === null ) {
237248 device = await serialLib . requestPort ( { } ) ;
238249 transport = new Transport ( device , true ) ;
250+ deviceInfo = device . getInfo ( ) ;
251+
252+ // Set up device lost callback
253+ transport . setDeviceLostCallback ( async ( ) => {
254+ if ( ! isConsoleClosed && ! isReconnecting ) {
255+ term . writeln ( "\n[DEVICE LOST] Device disconnected. Trying to reconnect..." ) ;
256+ await sleep ( parseInt ( reconnectDelay . value ) ) ;
257+ isReconnecting = true ;
258+
259+ const maxRetries = parseInt ( maxRetriesInput . value ) ;
260+ let retryCount = 0 ;
261+
262+ while ( retryCount < maxRetries && ! isConsoleClosed ) {
263+ retryCount ++ ;
264+ term . writeln ( `\n[RECONNECT] Attempt ${ retryCount } /${ maxRetries } ...` ) ;
265+
266+ if ( serialLib && serialLib . getPorts ) {
267+ const ports = await serialLib . getPorts ( ) ;
268+ if ( ports . length > 0 ) {
269+ const newDevice = ports . find (
270+ ( port ) =>
271+ port . getInfo ( ) . usbVendorId === deviceInfo . usbVendorId &&
272+ port . getInfo ( ) . usbProductId === deviceInfo . usbProductId ,
273+ ) ;
274+
275+ if ( newDevice ) {
276+ device = newDevice ;
277+ transport . updateDevice ( device ) ;
278+ term . writeln ( "[RECONNECT] Found previously authorized device, connecting..." ) ;
279+ await transport . connect ( parseInt ( consoleBaudrates . value ) ) ;
280+ term . writeln ( "[RECONNECT] Successfully reconnected!" ) ;
281+ consoleStopButton . style . display = "initial" ;
282+ resetButton . style . display = "initial" ;
283+ isReconnecting = false ;
284+
285+ startConsoleReading ( ) ;
286+ return ;
287+ }
288+ }
289+ }
290+
291+ if ( retryCount < maxRetries ) {
292+ term . writeln ( `[RECONNECT] Device not found, retrying in ${ parseInt ( reconnectDelay . value ) } ms...` ) ;
293+ await sleep ( parseInt ( reconnectDelay . value ) ) ;
294+ }
295+ }
296+
297+ if ( retryCount >= maxRetries ) {
298+ term . writeln ( "\n[RECONNECT] Failed to reconnect after 5 attempts. Please manually reconnect." ) ;
299+ isReconnecting = false ;
300+ }
301+ }
302+ } ) ;
239303 }
304+
240305 lblConsoleFor . style . display = "block" ;
241306 lblConsoleBaudrate . style . display = "none" ;
242307 consoleBaudrates . style . display = "none" ;
@@ -247,21 +312,45 @@ consoleStartButton.onclick = async () => {
247312
248313 await transport . connect ( parseInt ( consoleBaudrates . value ) ) ;
249314 isConsoleClosed = false ;
315+ isReconnecting = false ;
316+
317+ startConsoleReading ( ) ;
318+ } ;
319+
320+ /**
321+ * Start the console reading loop
322+ */
323+ async function startConsoleReading ( ) {
324+ if ( isConsoleClosed || ! transport ) return ;
250325
251- while ( true && ! isConsoleClosed ) {
326+ try {
252327 const readLoop = transport . rawRead ( ) ;
253- const { value, done } = await readLoop . next ( ) ;
254328
255- if ( done || ! value ) {
256- break ;
329+ while ( true && ! isConsoleClosed ) {
330+ const { value, done } = await readLoop . next ( ) ;
331+
332+ if ( done || ! value ) {
333+ break ;
334+ }
335+
336+ if ( value ) {
337+ term . write ( value ) ;
338+ }
339+ }
340+ } catch ( error ) {
341+ if ( ! isConsoleClosed ) {
342+ term . writeln ( `\n[CONSOLE ERROR] ${ error instanceof Error ? error . message : String ( error ) } ` ) ;
257343 }
258- term . write ( value ) ;
259344 }
260- console . log ( "quitting console" ) ;
261- } ;
345+
346+ if ( ! isConsoleClosed ) {
347+ term . writeln ( "\n[CONSOLE] Connection lost, waiting for reconnection..." ) ;
348+ }
349+ }
262350
263351consoleStopButton . onclick = async ( ) => {
264352 isConsoleClosed = true ;
353+ isReconnecting = false ;
265354 if ( transport ) {
266355 await transport . disconnect ( ) ;
267356 await transport . waitForUnlock ( 1500 ) ;
0 commit comments