@@ -18,18 +18,62 @@ def __init__(self, loop, protocol, *args, **kwargs):
1818 self .async_loop = loop
1919 self ._protocol : asyncio .BaseProtocol = protocol
2020 self .sync_serial = serial .serial_for_url (* args , ** kwargs )
21- self ._closing = False
2221 self ._write_buffer = []
23- self .set_write_buffer_limits ()
2422 self ._has_reader = False
2523 self ._has_writer = False
2624 self ._poll_wait_time = 0.0005
27-
28- # Asynchronous I/O requires non-blocking devices
2925 self .sync_serial .timeout = 0
3026 self .sync_serial .write_timeout = 0
31- loop .call_soon (protocol .connection_made , self )
32- loop .call_soon (self ._ensure_reader )
27+
28+ def setup (self ):
29+ """Prepare to read/write"""
30+ self .async_loop .call_soon (self ._protocol .connection_made , self )
31+ if os .name == "nt" :
32+ self ._has_reader = self .async_loop .call_later (
33+ self ._poll_wait_time , self ._poll_read
34+ )
35+ else :
36+ self .async_loop .add_reader (self .sync_serial .fileno (), self ._read_ready )
37+ self ._has_reader = True
38+
39+ def close (self , exc = None ):
40+ """Close the transport gracefully."""
41+ if not self .sync_serial :
42+ return
43+ with contextlib .suppress (Exception ):
44+ self .sync_serial .flush ()
45+
46+ if self ._has_reader :
47+ if os .name == "nt" :
48+ self ._has_reader .cancel ()
49+ else :
50+ self .async_loop .remove_reader (self .sync_serial .fileno ())
51+ self ._has_reader = False
52+ self .flush ()
53+ self .sync_serial .close ()
54+ self .sync_serial = None
55+ with contextlib .suppress (Exception ):
56+ self ._protocol .connection_lost (exc )
57+
58+ def write (self , data ):
59+ """Write some data to the transport."""
60+ self ._write_buffer .append (data )
61+ if not self ._has_writer :
62+ if os .name == "nt" :
63+ self ._has_writer = self .async_loop .call_soon (self ._poll_write )
64+ else :
65+ self .async_loop .add_writer (self .sync_serial .fileno (), self ._write_ready )
66+ self ._has_writer = True
67+
68+ def flush (self ):
69+ """Clear output buffer and stops any more data being written"""
70+ if self ._has_writer :
71+ if os .name == "nt" :
72+ self ._has_writer .cancel ()
73+ else :
74+ self .async_loop .remove_writer (self .sync_serial .fileno ())
75+ self ._has_writer = False
76+ self ._write_buffer .clear ()
3377
3478 # ------------------------------------------------
3579 # Dummy methods needed to please asyncio.Transport.
@@ -75,160 +119,61 @@ def pause_reading(self):
75119 def resume_reading (self ):
76120 """Resume receiver."""
77121
78- # ------------------------------------------------
79-
80122 def is_closing (self ):
81123 """Return True if the transport is closing or closed."""
82- return self . _closing
124+ return False
83125
84- def close (self ):
85- """Close the transport gracefully."""
86- if self ._closing :
87- return
88- self ._closing = True
89- self ._remove_reader ()
90- self ._remove_writer ()
91- self .async_loop .call_soon (self ._call_connection_lost , None )
126+ def abort (self ):
127+ """Close the transport immediately."""
128+ self .close ()
129+
130+ # ------------------------------------------------
92131
93132 def _read_ready (self ):
94133 """Test if there are data waiting."""
95134 try :
96- data = self .sync_serial .read (1024 )
97- except serial .SerialException as exc :
98- self .async_loop .call_soon (self ._call_connection_lost , exc )
99- self .close ()
100- else :
101- if data :
135+ if data := self .sync_serial .read (1024 ):
102136 self ._protocol .data_received (data )
103-
104- def write (self , data ):
105- """Write some data to the transport."""
106- if self ._closing :
107- return
108-
109- self ._write_buffer .append (data )
110- self ._ensure_writer ()
111-
112- def abort (self ):
113- """Close the transport immediately."""
114- self .close ()
115-
116- def flush (self ):
117- """Clear output buffer and stops any more data being written"""
118- self ._remove_writer ()
119- self ._write_buffer .clear ()
137+ except serial .SerialException as exc :
138+ self .close (exc = exc )
120139
121140 def _write_ready (self ):
122141 """Asynchronously write buffered data."""
123142 data = b"" .join (self ._write_buffer )
124- assert data , "Write buffer should not be empty"
125-
126- self ._write_buffer .clear ()
127-
128143 try :
129- nlen = self .sync_serial .write (data )
144+ if nlen := self .sync_serial .write (data ) < len (data ):
145+ self ._write_buffer = data [nlen :]
146+ return True
147+ self .flush ()
130148 except (BlockingIOError , InterruptedError ):
131- self . _write_buffer . append ( data )
149+ return True
132150 except serial .SerialException as exc :
133- self .async_loop .call_soon (self ._call_connection_lost , exc )
134- self .abort ()
135- else :
136- if nlen == len (data ):
137- assert not self .get_write_buffer_size ()
138- self ._remove_writer ()
139- if self ._closing and not self .get_write_buffer_size ():
140- self .close ()
141- return
142-
143- assert 0 <= nlen < len (data )
144- data = data [nlen :]
145- self ._write_buffer .append (data ) # Try again later
146- assert self ._has_writer
147-
148- if os .name == "nt" :
149-
150- def _poll_read (self ):
151- if self ._has_reader and not self ._closing :
152- try :
153- self ._has_reader = self .async_loop .call_later (
154- self ._poll_wait_time , self ._poll_read
155- )
156- if self .sync_serial .in_waiting :
157- self ._read_ready ()
158- except serial .SerialException as exc :
159- self .async_loop .call_soon (self ._call_connection_lost , exc )
160- self .abort ()
161-
162- def _ensure_reader (self ):
163- if not self ._has_reader and not self ._closing :
151+ self .close (exc = exc )
152+ return False
153+
154+ def _poll_read (self ):
155+ if self ._has_reader :
156+ try :
164157 self ._has_reader = self .async_loop .call_later (
165158 self ._poll_wait_time , self ._poll_read
166159 )
160+ if self .sync_serial .in_waiting :
161+ self ._read_ready ()
162+ except serial .SerialException as exc :
163+ self .close (exc = exc )
167164
168- def _remove_reader (self ):
169- if self ._has_reader :
170- self ._has_reader .cancel ()
171- self ._has_reader = False
172-
173- def _poll_write (self ):
174- if self ._has_writer and not self ._closing :
175- self ._has_writer = self .async_loop .call_later (
176- self ._poll_wait_time , self ._poll_write
177- )
178- self ._write_ready ()
179-
180- def _ensure_writer (self ):
181- if not self ._has_writer and not self ._closing :
182- self ._has_writer = self .async_loop .call_soon (self ._poll_write )
183-
184- def _remove_writer (self ):
185- if self ._has_writer :
186- self ._has_writer .cancel ()
187- self ._has_writer = False
188-
189- else :
190-
191- def _ensure_reader (self ):
192- if (not self ._has_reader ) and (not self ._closing ):
193- self .async_loop .add_reader (self .sync_serial .fileno (), self ._read_ready )
194- self ._has_reader = True
195-
196- def _remove_reader (self ):
197- if self ._has_reader :
198- self .async_loop .remove_reader (self .sync_serial .fileno ())
199- self ._has_reader = False
200-
201- def _ensure_writer (self ):
202- if (not self ._has_writer ) and (not self ._closing ):
203- self .async_loop .add_writer (self .sync_serial .fileno (), self ._write_ready )
204- self ._has_writer = True
205-
206- def _remove_writer (self ):
207- if self ._has_writer :
208- self .async_loop .remove_writer (self .sync_serial .fileno ())
209- self ._has_writer = False
210-
211- def _call_connection_lost (self , exc ):
212- """Close the connection."""
213- assert self ._closing
214- assert not self ._has_writer
215- assert not self ._has_reader
216- if self .sync_serial :
217- with contextlib .suppress (Exception ):
218- self .sync_serial .flush ()
219-
220- self .sync_serial .close ()
221- self .sync_serial = None
222- if self ._protocol :
223- with contextlib .suppress (Exception ):
224- self ._protocol .connection_lost (exc )
225-
226- self ._write_buffer .clear ()
227- self ._write_buffer .clear ()
165+ def _poll_write (self ):
166+ if not self ._has_writer :
167+ return
168+ if self ._write_ready ():
169+ self ._has_writer = self .async_loop .call_later (
170+ self ._poll_wait_time , self ._poll_write
171+ )
228172
229173
230174async def create_serial_connection (loop , protocol_factory , * args , ** kwargs ):
231175 """Create a connection to a new serial port instance."""
232176 protocol = protocol_factory ()
233177 transport = SerialTransport (loop , protocol , * args , ** kwargs )
178+ loop .call_soon (transport .setup )
234179 return transport , protocol
0 commit comments