From 421bc71bb7fd568db86c68b1c131a4a41ac66a4f Mon Sep 17 00:00:00 2001 From: zjs81 Date: Sat, 7 Mar 2026 12:55:15 -0700 Subject: [PATCH] Enhance USB port opening and reading logic with improved error handling and debug logging --- lib/services/usb_serial_service_web.dart | 37 +++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/services/usb_serial_service_web.dart b/lib/services/usb_serial_service_web.dart index 88aa81d..86f0b1e 100644 --- a/lib/services/usb_serial_service_web.dart +++ b/lib/services/usb_serial_service_web.dart @@ -268,9 +268,23 @@ class UsbSerialService { return null; } - Future _openPort(JSObject port, int baudRate) { - final options = JSObject()..['baudRate'] = baudRate.toJS; - return port.callMethod>('open'.toJS, options).toDart; + Future _openPort(JSObject port, int baudRate) async { + final options = JSObject() + ..['baudRate'] = baudRate.toJS + ..['flowControl'] = 'none'.toJS; + await port.callMethod>('open'.toJS, options).toDart; + + // Prevent ESP32 USB-CDC reset: hold DTR=true, RTS=false after open. + try { + final signals = JSObject() + ..['dataTerminalReady'] = true.toJS + ..['requestToSend'] = false.toJS; + await port + .callMethod>('setSignals'.toJS, signals) + .toDart; + } catch (_) { + // setSignals may not be supported on all browsers/devices. + } } Future _cleanupFailedConnect() async { @@ -324,8 +338,12 @@ class UsbSerialService { Future _pumpReads() async { final reader = _reader; - if (reader == null) return; + if (reader == null) { + _debugLogService?.warn('_pumpReads: reader is null', tag: 'USB Serial'); + return; + } + _debugLogService?.info('_pumpReads: started', tag: 'USB Serial'); try { while (_status == UsbSerialStatus.connected && identical(reader, _reader)) { @@ -333,6 +351,7 @@ class UsbSerialService { .callMethod>('read'.toJS) .toDart; if (result == null) { + _debugLogService?.warn('_pumpReads: null result', tag: 'USB Serial'); break; } final resultObject = result as JSObject; @@ -340,20 +359,30 @@ class UsbSerialService { final doneValue = resultObject.getProperty('done'.toJS); final done = doneValue != null && doneValue.dartify() == true; if (done) { + _debugLogService?.info('_pumpReads: done=true', tag: 'USB Serial'); break; } final value = resultObject.getProperty('value'.toJS); final bytes = _coerceBytes(value); if (bytes != null && bytes.isNotEmpty) { + _debugLogService?.info( + 'USB RX raw: ${bytes.length} byte(s)', + tag: 'USB Serial', + ); _ingestRawBytes(bytes); } } } catch (error, stackTrace) { + _debugLogService?.error( + '_pumpReads error: $error', + tag: 'USB Serial', + ); if (_status == UsbSerialStatus.connected) { _addFrameError(error, stackTrace); } } finally { + _debugLogService?.info('_pumpReads: ended', tag: 'USB Serial'); _releaseLock(reader); if (_status == UsbSerialStatus.connected && identical(reader, _reader)) { _addFrameError(StateError('USB serial connection closed'));