jmri_loconet.transport.tcp_port
TcpPort — LocoNet over TCP (LbServer / network bridge).
1"""``TcpPort`` — LocoNet over TCP (LbServer / network bridge).""" 2from __future__ import annotations 3 4import asyncio 5from typing import TYPE_CHECKING 6 7from jmri_loconet.transport.port import LocoNetPort 8 9if TYPE_CHECKING: 10 from asyncio import StreamReader, StreamWriter 11 12 13class TcpPort(LocoNetPort): 14 """LocoNet over a TCP socket (e.g. JMRI's LbServer or Digitrax LNWI).""" 15 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 read_byte(self) -> int: 27 data = await self._reader.readexactly(1) 28 return data[0] 29 30 async def read_exact(self, n: int) -> bytes: 31 return await self._reader.readexactly(n) 32 33 async def write_frame(self, frame: bytes) -> None: 34 if not self._open: 35 raise RuntimeError("port is closed") 36 self._writer.write(frame) 37 await self._writer.drain() 38 39 async def aclose(self) -> None: 40 if not self._open: 41 return 42 self._open = False 43 self._writer.close() 44 import contextlib # noqa: PLC0415 45 with contextlib.suppress(Exception): 46 await self._writer.wait_closed() 47 48 @property 49 def is_open(self) -> bool: 50 return self._open
14class TcpPort(LocoNetPort): 15 """LocoNet over a TCP socket (e.g. JMRI's LbServer or Digitrax LNWI).""" 16 17 def __init__(self, reader: StreamReader, writer: StreamWriter) -> None: 18 self._reader = reader 19 self._writer = writer 20 self._open = True 21 22 @classmethod 23 async def open(cls, host: str, port: int) -> TcpPort: 24 reader, writer = await asyncio.open_connection(host, port) 25 return cls(reader=reader, writer=writer) 26 27 async def read_byte(self) -> int: 28 data = await self._reader.readexactly(1) 29 return data[0] 30 31 async def read_exact(self, n: int) -> bytes: 32 return await self._reader.readexactly(n) 33 34 async def write_frame(self, frame: bytes) -> None: 35 if not self._open: 36 raise RuntimeError("port is closed") 37 self._writer.write(frame) 38 await self._writer.drain() 39 40 async def aclose(self) -> None: 41 if not self._open: 42 return 43 self._open = False 44 self._writer.close() 45 import contextlib # noqa: PLC0415 46 with contextlib.suppress(Exception): 47 await self._writer.wait_closed() 48 49 @property 50 def is_open(self) -> bool: 51 return self._open
LocoNet over a TCP socket (e.g. JMRI's LbServer or Digitrax LNWI).
async def
write_frame(self, frame: bytes) -> None:
34 async def write_frame(self, frame: bytes) -> None: 35 if not self._open: 36 raise RuntimeError("port is closed") 37 self._writer.write(frame) 38 await self._writer.drain()
Write a complete LocoNet frame (opcode + payload + checksum).