jmri_openlcb.transport

OpenLCB byte-stream transport.

1"""OpenLCB byte-stream transport."""
2from jmri_openlcb.transport.loopback import LoopbackPort, loopback_pair
3from jmri_openlcb.transport.port import BytePort
4from jmri_openlcb.transport.serial_port import SerialPort
5from jmri_openlcb.transport.tcp_port import TcpPort
6
7__all__ = ["BytePort", "LoopbackPort", "SerialPort", "TcpPort", "loopback_pair"]
class BytePort(abc.ABC):
 7class BytePort(ABC):
 8    @abstractmethod
 9    async def write(self, data: bytes) -> None: ...
10    @abstractmethod
11    async def read_byte(self) -> int: ...
12    @abstractmethod
13    async def aclose(self) -> None: ...
14    @property
15    @abstractmethod
16    def is_open(self) -> bool: ...

Helper class that provides a standard way to create an ABC using inheritance.

@abstractmethod
async def write(self, data: bytes) -> None:
8    @abstractmethod
9    async def write(self, data: bytes) -> None: ...
@abstractmethod
async def read_byte(self) -> int:
10    @abstractmethod
11    async def read_byte(self) -> int: ...
@abstractmethod
async def aclose(self) -> None:
12    @abstractmethod
13    async def aclose(self) -> None: ...
is_open: bool
14    @property
15    @abstractmethod
16    def is_open(self) -> bool: ...
class LoopbackPort(jmri_openlcb.transport.BytePort):
 9class LoopbackPort(BytePort):
10    def __init__(self, read_q: asyncio.Queue[int], write_q: asyncio.Queue[int]) -> None:
11        self._r = read_q
12        self._w = write_q
13        self._open = True
14
15    async def write(self, data: bytes) -> None:
16        if not self._open:
17            raise RuntimeError("port is closed")
18        for b in data:
19            await self._w.put(b)
20
21    async def read_byte(self) -> int:
22        return await self._r.get()
23
24    async def aclose(self) -> None:
25        self._open = False
26
27    @property
28    def is_open(self) -> bool:
29        return self._open

Helper class that provides a standard way to create an ABC using inheritance.

LoopbackPort( read_q: asyncio.queues.Queue[int], write_q: asyncio.queues.Queue[int])
10    def __init__(self, read_q: asyncio.Queue[int], write_q: asyncio.Queue[int]) -> None:
11        self._r = read_q
12        self._w = write_q
13        self._open = True
async def write(self, data: bytes) -> None:
15    async def write(self, data: bytes) -> None:
16        if not self._open:
17            raise RuntimeError("port is closed")
18        for b in data:
19            await self._w.put(b)
async def read_byte(self) -> int:
21    async def read_byte(self) -> int:
22        return await self._r.get()
async def aclose(self) -> None:
24    async def aclose(self) -> None:
25        self._open = False
is_open: bool
27    @property
28    def is_open(self) -> bool:
29        return self._open
class SerialPort(jmri_openlcb.transport.BytePort):
18class SerialPort(BytePort):
19    def __init__(self, reader: StreamReader, writer: StreamWriter) -> None:
20        self._reader = reader
21        self._writer = writer
22        self._open = True
23
24    @classmethod
25    async def open(cls, port: str, baud: int = DEFAULT_BAUD) -> SerialPort:
26        import serial_asyncio  # noqa: PLC0415
27        reader, writer = await serial_asyncio.open_serial_connection(url=port, baudrate=baud)
28        return cls(reader=reader, writer=writer)
29
30    async def write(self, data: bytes) -> None:
31        if not self._open:
32            raise RuntimeError("port is closed")
33        self._writer.write(data)
34        await self._writer.drain()
35
36    async def read_byte(self) -> int:
37        data = await self._reader.readexactly(1)
38        return data[0]
39
40    async def aclose(self) -> None:
41        if not self._open:
42            return
43        self._open = False
44        self._writer.close()
45        with contextlib.suppress(Exception):
46            await self._writer.wait_closed()
47
48    @property
49    def is_open(self) -> bool:
50        return self._open

Helper class that provides a standard way to create an ABC using inheritance.

SerialPort( reader: asyncio.streams.StreamReader, writer: asyncio.streams.StreamWriter)
19    def __init__(self, reader: StreamReader, writer: StreamWriter) -> None:
20        self._reader = reader
21        self._writer = writer
22        self._open = True
@classmethod
async def open( cls, port: str, baud: int = 333333) -> SerialPort:
24    @classmethod
25    async def open(cls, port: str, baud: int = DEFAULT_BAUD) -> SerialPort:
26        import serial_asyncio  # noqa: PLC0415
27        reader, writer = await serial_asyncio.open_serial_connection(url=port, baudrate=baud)
28        return cls(reader=reader, writer=writer)
async def write(self, data: bytes) -> None:
30    async def write(self, data: bytes) -> None:
31        if not self._open:
32            raise RuntimeError("port is closed")
33        self._writer.write(data)
34        await self._writer.drain()
async def read_byte(self) -> int:
36    async def read_byte(self) -> int:
37        data = await self._reader.readexactly(1)
38        return data[0]
async def aclose(self) -> None:
40    async def aclose(self) -> None:
41        if not self._open:
42            return
43        self._open = False
44        self._writer.close()
45        with contextlib.suppress(Exception):
46            await self._writer.wait_closed()
is_open: bool
48    @property
49    def is_open(self) -> bool:
50        return self._open
class TcpPort(jmri_openlcb.transport.BytePort):
15class TcpPort(BytePort):
16    def __init__(self, reader: StreamReader, writer: StreamWriter) -> None:
17        self._reader = reader
18        self._writer = writer
19        self._open = True
20
21    @classmethod
22    async def open(cls, host: str, port: int) -> TcpPort:
23        reader, writer = await asyncio.open_connection(host, port)
24        return cls(reader=reader, writer=writer)
25
26    async def write(self, data: bytes) -> None:
27        if not self._open:
28            raise RuntimeError("port is closed")
29        self._writer.write(data)
30        await self._writer.drain()
31
32    async def read_byte(self) -> int:
33        data = await self._reader.readexactly(1)
34        return data[0]
35
36    async def aclose(self) -> None:
37        if not self._open:
38            return
39        self._open = False
40        self._writer.close()
41        with contextlib.suppress(Exception):
42            await self._writer.wait_closed()
43
44    @property
45    def is_open(self) -> bool:
46        return self._open

Helper class that provides a standard way to create an ABC using inheritance.

TcpPort( reader: asyncio.streams.StreamReader, writer: asyncio.streams.StreamWriter)
16    def __init__(self, reader: StreamReader, writer: StreamWriter) -> None:
17        self._reader = reader
18        self._writer = writer
19        self._open = True
@classmethod
async def open(cls, host: str, port: int) -> TcpPort:
21    @classmethod
22    async def open(cls, host: str, port: int) -> TcpPort:
23        reader, writer = await asyncio.open_connection(host, port)
24        return cls(reader=reader, writer=writer)
async def write(self, data: bytes) -> None:
26    async def write(self, data: bytes) -> None:
27        if not self._open:
28            raise RuntimeError("port is closed")
29        self._writer.write(data)
30        await self._writer.drain()
async def read_byte(self) -> int:
32    async def read_byte(self) -> int:
33        data = await self._reader.readexactly(1)
34        return data[0]
async def aclose(self) -> None:
36    async def aclose(self) -> None:
37        if not self._open:
38            return
39        self._open = False
40        self._writer.close()
41        with contextlib.suppress(Exception):
42            await self._writer.wait_closed()
is_open: bool
44    @property
45    def is_open(self) -> bool:
46        return self._open
def loopback_pair() -> tuple[LoopbackPort, LoopbackPort]:
32def loopback_pair() -> tuple[LoopbackPort, LoopbackPort]:
33    a_to_b: asyncio.Queue[int] = asyncio.Queue()
34    b_to_a: asyncio.Queue[int] = asyncio.Queue()
35    return LoopbackPort(b_to_a, a_to_b), LoopbackPort(a_to_b, b_to_a)