11from contextlib import asynccontextmanager
22from dataclasses import dataclass , field
33
4+ from anyio import (
5+ create_memory_object_stream ,
6+ )
7+ from anyio ._backends ._asyncio import StreamReaderWrapper , StreamWriterWrapper
48from anyio .abc import ObjectStream
5- from anyio .to_thread import run_sync
6- from serial import Serial , serial_for_url
9+ from anyio .streams .stapled import StapledObjectStream
10+ from serial import serial_for_url
11+ from serial_asyncio import open_serial_connection
712
813from jumpstarter .driver import Driver , exportstream
914
15+ LOOP = "loop://"
16+
1017
1118@dataclass (kw_only = True )
1219class AsyncSerial (ObjectStream ):
13- device : Serial
20+ reader : StreamReaderWrapper
21+ writer : StreamWriterWrapper
1422
1523 async def send (self , item ):
16- await run_sync ( self .device . write , item )
24+ await self .writer . send ( item )
1725
1826 async def receive (self ):
19- size = max (self .device .in_waiting , 1 )
20- return await run_sync (self .device .read , size )
27+ return await self .reader .receive ()
2128
2229 async def send_eof (self ):
23- await run_sync ( self . device . close )
30+ pass
2431
2532 async def aclose (self ):
26- await run_sync (self .device .close )
33+ await self .writer .aclose ()
34+ await self .reader .aclose ()
2735
2836
2937@dataclass (kw_only = True )
@@ -35,7 +43,7 @@ class PySerial(Driver):
3543 def __post_init__ (self ):
3644 if hasattr (super (), "__post_init__" ):
3745 super ().__post_init__ ()
38- if self .check_present :
46+ if self .check_present and self . url != LOOP :
3947 serial_for_url (self .url , baudrate = self .baudrate )
4048
4149 @classmethod
@@ -46,7 +54,16 @@ def client(cls) -> str:
4654 @asynccontextmanager
4755 async def connect (self ):
4856 self .logger .info ("Connecting to %s, baudrate: %d" , self .url , self .baudrate )
49- device = await run_sync (serial_for_url , self .url , self .baudrate )
50- async with AsyncSerial (device = device ) as stream :
51- yield stream
52- self .logger .info ("Disconnected from %s" , self .url )
57+ if self .url != LOOP :
58+ reader , writer = await open_serial_connection (url = self .url , baudrate = self .baudrate , limit = 1 )
59+ writer .transport .set_write_buffer_limits (high = 4096 , low = 0 )
60+ async with AsyncSerial (
61+ reader = StreamReaderWrapper (reader ),
62+ writer = StreamWriterWrapper (writer ),
63+ ) as stream :
64+ yield stream
65+ self .logger .info ("Disconnected from %s" , self .url )
66+ else :
67+ tx , rx = create_memory_object_stream [bytes ](32 )
68+ async with StapledObjectStream (tx , rx ) as stream :
69+ yield stream
0 commit comments