1212class SerialTransport (asyncio .Transport ):
1313 """An asyncio serial transport."""
1414
15+ force_poll : bool = False
16+
1517 def __init__ (self , loop , protocol , * args , ** kwargs ):
1618 """Initialize."""
1719 super ().__init__ ()
1820 self .async_loop = loop
1921 self ._protocol : asyncio .BaseProtocol = protocol
2022 self .sync_serial = serial .serial_for_url (* args , ** kwargs )
2123 self ._write_buffer = []
22- self ._has_reader = False
23- self ._has_writer = False
24+ self .poll_task = None
2425 self ._poll_wait_time = 0.0005
2526 self .sync_serial .timeout = 0
2627 self .sync_serial .write_timeout = 0
2728
2829 def setup (self ):
2930 """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- )
31+ if os .name == "nt" or self .force_poll :
32+ self .poll_task = asyncio .create_task (self ._polling_task ())
3533 else :
3634 self .async_loop .add_reader (self .sync_serial .fileno (), self ._read_ready )
37- self ._has_reader = True
35+ self .async_loop . call_soon ( self . _protocol . connection_made , self )
3836
3937 def close (self , exc = None ):
4038 """Close the transport gracefully."""
@@ -43,13 +41,13 @@ def close(self, exc=None):
4341 with contextlib .suppress (Exception ):
4442 self .sync_serial .flush ()
4543
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
5244 self .flush ()
45+ if self .poll_task :
46+ self .poll_task .cancel ()
47+ _ = asyncio .ensure_future (self .poll_task )
48+ self .poll_task = None
49+ else :
50+ self .async_loop .remove_reader (self .sync_serial .fileno ())
5351 self .sync_serial .close ()
5452 self .sync_serial = None
5553 with contextlib .suppress (Exception ):
@@ -58,21 +56,13 @@ def close(self, exc=None):
5856 def write (self , data ):
5957 """Write some data to the transport."""
6058 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
59+ if not self .poll_task :
60+ self .async_loop .add_writer (self .sync_serial .fileno (), self ._write_ready )
6761
6862 def flush (self ):
6963 """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
64+ if not self .poll_task :
65+ self .async_loop .remove_writer (self .sync_serial .fileno ())
7666 self ._write_buffer .clear ()
7767
7868 # ------------------------------------------------
@@ -141,34 +131,32 @@ def _write_ready(self):
141131 """Asynchronously write buffered data."""
142132 data = b"" .join (self ._write_buffer )
143133 try :
144- if nlen := self .sync_serial .write (data ) < len (data ):
145- self ._write_buffer = data [nlen :]
146- return True
134+ if (nlen := self .sync_serial .write (data )) < len (data ):
135+ self ._write_buffer = [data [nlen :]]
136+ if not self .poll_task :
137+ self .async_loop .add_writer (
138+ self .sync_serial .fileno (), self ._write_ready
139+ )
140+ return
147141 self .flush ()
148142 except (BlockingIOError , InterruptedError ):
149- return True
143+ return
150144 except serial .SerialException as exc :
151145 self .close (exc = exc )
152- return False
153146
154- def _poll_read (self ):
155- if self ._has_reader :
156- try :
157- self ._has_reader = self .async_loop .call_later (
158- self ._poll_wait_time , self ._poll_read
159- )
147+ async def _polling_task (self ):
148+ """Poll and try to read/write."""
149+ try :
150+ while True :
151+ await asyncio .sleep (self ._poll_wait_time )
152+ while self ._write_buffer :
153+ self ._write_ready ()
160154 if self .sync_serial .in_waiting :
161155 self ._read_ready ()
162- except serial .SerialException as exc :
163- self .close (exc = exc )
164-
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- )
156+ except serial .SerialException as exc :
157+ self .close (exc = exc )
158+ except asyncio .CancelledError :
159+ pass
172160
173161
174162async def create_serial_connection (loop , protocol_factory , * args , ** kwargs ):
0 commit comments