jmri_nce.transport.serial_port
SerialPort — pyserial-asyncio NCE transport.
PowerCab USB and PowerPro USB present as standard USB-serial devices. Default baud is 9600 (PowerPro) but some configurations use 19200 or 57600; user is expected to set the right value in the connection settings.
1"""``SerialPort`` — pyserial-asyncio NCE transport. 2 3PowerCab USB and PowerPro USB present as standard USB-serial devices. 4Default baud is 9600 (PowerPro) but some configurations use 19200 or 557600; user is expected to set the right value in the connection settings. 6""" 7from __future__ import annotations 8 9import contextlib 10from typing import TYPE_CHECKING 11 12from jmri_nce.transport.port import BytePort 13 14if TYPE_CHECKING: 15 from asyncio import StreamReader, StreamWriter 16 17 18DEFAULT_BAUD = 9600 # PowerPro default; PowerCab uses the same. 19 20 21class SerialPort(BytePort): 22 """NCE over an async serial port.""" 23 24 def __init__(self, reader: StreamReader, writer: StreamWriter) -> None: 25 self._reader = reader 26 self._writer = writer 27 self._open = True 28 29 @classmethod 30 async def open(cls, port: str, baud: int = DEFAULT_BAUD) -> SerialPort: 31 """Open *port* (e.g. ``"COM7"`` or ``"/dev/ttyUSB0"``).""" 32 import serial_asyncio # noqa: PLC0415 33 reader, writer = await serial_asyncio.open_serial_connection( 34 url=port, baudrate=baud 35 ) 36 return cls(reader=reader, writer=writer) 37 38 async def write(self, data: bytes) -> None: 39 if not self._open: 40 raise RuntimeError("port is closed") 41 self._writer.write(data) 42 await self._writer.drain() 43 44 async def read_exact(self, n: int) -> bytes: 45 return await self._reader.readexactly(n) 46 47 async def read_pending(self) -> bytes: 48 """Return whatever bytes are already buffered without waiting. 49 50 ``StreamReader._buffer`` is private API but stable across asyncio 51 releases; ``read()`` blocks until at least one byte arrives, which 52 is the opposite of what the drain needs. 53 """ 54 buf = self._reader._buffer # type: ignore[attr-defined] 55 if not buf: 56 return b"" 57 n = len(buf) 58 return await self._reader.readexactly(n) 59 60 async def aclose(self) -> None: 61 if not self._open: 62 return 63 self._open = False 64 self._writer.close() 65 with contextlib.suppress(Exception): 66 await self._writer.wait_closed() 67 68 @property 69 def is_open(self) -> bool: 70 return self._open
DEFAULT_BAUD =
9600
22class SerialPort(BytePort): 23 """NCE over an async serial port.""" 24 25 def __init__(self, reader: StreamReader, writer: StreamWriter) -> None: 26 self._reader = reader 27 self._writer = writer 28 self._open = True 29 30 @classmethod 31 async def open(cls, port: str, baud: int = DEFAULT_BAUD) -> SerialPort: 32 """Open *port* (e.g. ``"COM7"`` or ``"/dev/ttyUSB0"``).""" 33 import serial_asyncio # noqa: PLC0415 34 reader, writer = await serial_asyncio.open_serial_connection( 35 url=port, baudrate=baud 36 ) 37 return cls(reader=reader, writer=writer) 38 39 async def write(self, data: bytes) -> None: 40 if not self._open: 41 raise RuntimeError("port is closed") 42 self._writer.write(data) 43 await self._writer.drain() 44 45 async def read_exact(self, n: int) -> bytes: 46 return await self._reader.readexactly(n) 47 48 async def read_pending(self) -> bytes: 49 """Return whatever bytes are already buffered without waiting. 50 51 ``StreamReader._buffer`` is private API but stable across asyncio 52 releases; ``read()`` blocks until at least one byte arrives, which 53 is the opposite of what the drain needs. 54 """ 55 buf = self._reader._buffer # type: ignore[attr-defined] 56 if not buf: 57 return b"" 58 n = len(buf) 59 return await self._reader.readexactly(n) 60 61 async def aclose(self) -> None: 62 if not self._open: 63 return 64 self._open = False 65 self._writer.close() 66 with contextlib.suppress(Exception): 67 await self._writer.wait_closed() 68 69 @property 70 def is_open(self) -> bool: 71 return self._open
NCE over an async serial port.
30 @classmethod 31 async def open(cls, port: str, baud: int = DEFAULT_BAUD) -> SerialPort: 32 """Open *port* (e.g. ``"COM7"`` or ``"/dev/ttyUSB0"``).""" 33 import serial_asyncio # noqa: PLC0415 34 reader, writer = await serial_asyncio.open_serial_connection( 35 url=port, baudrate=baud 36 ) 37 return cls(reader=reader, writer=writer)
Open port (e.g. "COM7" or "/dev/ttyUSB0").
async def
read_pending(self) -> bytes:
48 async def read_pending(self) -> bytes: 49 """Return whatever bytes are already buffered without waiting. 50 51 ``StreamReader._buffer`` is private API but stable across asyncio 52 releases; ``read()`` blocks until at least one byte arrives, which 53 is the opposite of what the drain needs. 54 """ 55 buf = self._reader._buffer # type: ignore[attr-defined] 56 if not buf: 57 return b"" 58 n = len(buf) 59 return await self._reader.readexactly(n)
Return whatever bytes are already buffered without waiting.
StreamReader._buffer is private API but stable across asyncio
releases; read() blocks until at least one byte arrives, which
is the opposite of what the drain needs.