@@ -7,51 +7,53 @@ def do_repl_main_loop(
7
7
state , console_in , console_out_write , * , escape_non_printable , code_to_inject , file_to_inject
8
8
):
9
9
while True :
10
- console_in .waitchar (state .transport .serial )
11
- c = console_in .readchar ()
12
- if c :
13
- if c in (b"\x1d " , b"\x18 " ): # ctrl-] or ctrl-x, quit
14
- break
15
- elif c == b"\x04 " : # ctrl-D
16
- # special handling needed for ctrl-D if filesystem is mounted
17
- state .transport .write_ctrl_d (console_out_write )
18
- elif c == b"\x0a " and code_to_inject is not None : # ctrl-j, inject code
19
- state .transport .serial .write (code_to_inject )
20
- elif c == b"\x0b " and file_to_inject is not None : # ctrl-k, inject script
21
- console_out_write (bytes ("Injecting %s\r \n " % file_to_inject , "utf8" ))
22
- state .transport .enter_raw_repl (soft_reset = False )
23
- with open (file_to_inject , "rb" ) as f :
24
- pyfile = f .read ()
25
- try :
26
- state .transport .exec_raw_no_follow (pyfile )
27
- except TransportError as er :
28
- console_out_write (b"Error:\r \n " )
29
- console_out_write (er )
30
- state .transport .exit_raw_repl ()
31
- else :
32
- state .transport .serial .write (c )
33
-
34
10
try :
11
+ console_in .waitchar (state .transport .serial )
12
+ c = console_in .readchar ()
13
+ if c :
14
+ if c in (b"\x1d " , b"\x18 " ): # ctrl-] or ctrl-x, quit
15
+ break
16
+ elif c == b"\x04 " : # ctrl-D
17
+ # special handling needed for ctrl-D if filesystem is mounted
18
+ state .transport .write_ctrl_d (console_out_write )
19
+ elif c == b"\x0a " and code_to_inject is not None : # ctrl-j, inject code
20
+ state .transport .serial .write (code_to_inject )
21
+ elif c == b"\x0b " and file_to_inject is not None : # ctrl-k, inject script
22
+ console_out_write (bytes ("Injecting %s\r \n " % file_to_inject , "utf8" ))
23
+ state .transport .enter_raw_repl (soft_reset = False )
24
+ with open (file_to_inject , "rb" ) as f :
25
+ pyfile = f .read ()
26
+ try :
27
+ state .transport .exec_raw_no_follow (pyfile )
28
+ except TransportError as er :
29
+ console_out_write (b"Error:\r \n " )
30
+ console_out_write (er )
31
+ state .transport .exit_raw_repl ()
32
+ else :
33
+ state .transport .serial .write (c )
34
+
35
35
n = state .transport .serial .inWaiting ()
36
- except OSError as er :
37
- if er .args [0 ] == 5 : # IO error, device disappeared
38
- print ("device disconnected" )
39
- break
36
+ if n > 0 :
37
+ dev_data_in = state .transport .serial .read (n )
38
+ if dev_data_in is not None :
39
+ if escape_non_printable :
40
+ # Pass data through to the console, with escaping of non-printables.
41
+ console_data_out = bytearray ()
42
+ for c in dev_data_in :
43
+ if c in (8 , 9 , 10 , 13 , 27 ) or 32 <= c <= 126 :
44
+ console_data_out .append (c )
45
+ else :
46
+ console_data_out .extend (b"[%02x]" % c )
47
+ else :
48
+ console_data_out = dev_data_in
49
+ console_out_write (console_data_out )
40
50
41
- if n > 0 :
42
- dev_data_in = state .transport .serial .read (n )
43
- if dev_data_in is not None :
44
- if escape_non_printable :
45
- # Pass data through to the console, with escaping of non-printables.
46
- console_data_out = bytearray ()
47
- for c in dev_data_in :
48
- if c in (8 , 9 , 10 , 13 , 27 ) or 32 <= c <= 126 :
49
- console_data_out .append (c )
50
- else :
51
- console_data_out .extend (b"[%02x]" % c )
52
- else :
53
- console_data_out = dev_data_in
54
- console_out_write (console_data_out )
51
+ except OSError as er :
52
+ if _is_disconnect_exception (er ):
53
+ return True
54
+ else :
55
+ raise
56
+ return False
55
57
56
58
57
59
def do_repl (state , args ):
@@ -86,7 +88,7 @@ def console_out_write(b):
86
88
capture_file .flush ()
87
89
88
90
try :
89
- do_repl_main_loop (
91
+ return do_repl_main_loop (
90
92
state ,
91
93
console ,
92
94
console_out_write ,
@@ -98,3 +100,22 @@ def console_out_write(b):
98
100
console .exit ()
99
101
if capture_file is not None :
100
102
capture_file .close ()
103
+
104
+
105
+ def _is_disconnect_exception (exception ):
106
+ """
107
+ Check if an exception indicates device disconnect.
108
+
109
+ Returns True if the exception indicates the device has disconnected,
110
+ False otherwise.
111
+ """
112
+ if isinstance (exception , OSError ):
113
+ if hasattr (exception , 'args' ) and len (exception .args ) > 0 :
114
+ # IO error, device disappeared
115
+ if exception .args [0 ] == 5 :
116
+ return True
117
+ # Check for common disconnect messages in the exception string
118
+ exception_str = str (exception )
119
+ disconnect_indicators = ["Write timeout" , "Device disconnected" , "ClearCommError failed" ]
120
+ return any (indicator in exception_str for indicator in disconnect_indicators )
121
+ return False
0 commit comments