Skip to content

Commit

Permalink
Prepare transport for listen (server).
Browse files Browse the repository at this point in the history
  • Loading branch information
janiversen committed Jun 22, 2023
1 parent 2be46d0 commit a6b135a
Show file tree
Hide file tree
Showing 9 changed files with 725 additions and 1,341 deletions.
68 changes: 34 additions & 34 deletions pymodbus/server/async_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from pymodbus.device import ModbusControlBlock, ModbusDeviceIdentification
from pymodbus.exceptions import NoSuchSlaveException
from pymodbus.factory import ServerDecoder
from pymodbus.framer import ModbusFramer
from pymodbus.logging import Log
from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.transaction import (
Expand All @@ -20,6 +21,7 @@
ModbusTlsFramer,
)
from pymodbus.transport.serial_asyncio import create_serial_connection
from pymodbus.transport.transport import CommParams, Transport


with suppress(ImportError):
Expand Down Expand Up @@ -64,7 +66,7 @@ def sslctx_provider(
# --------------------------------------------------------------------------- #


class ModbusServerRequestHandler(asyncio.BaseProtocol):
class ModbusServerRequestHandler(Transport):
"""Implements modbus slave wire protocol.
This uses the asyncio.Protocol to implement the server protocol.
Expand All @@ -78,12 +80,20 @@ class ModbusServerRequestHandler(asyncio.BaseProtocol):

def __init__(self, owner):
"""Initialize."""
params = CommParams(
comm_name="server",
reconnect_delay=0.0,
reconnect_delay_max=0.0,
timeout_connect=0.0,
)
super().__init__(params, True)
self.server = owner
self.running = False
self.receive_queue = asyncio.Queue()
self.handler_task = None # coroutine to be run on asyncio loop
self._sent = b"" # for handle_local_echo
self.client_address = (None, None)
self.framer: ModbusFramer = None

def _log_exception(self):
"""Show log exception."""
Expand All @@ -108,13 +118,11 @@ def connection_made(self, transport):
self.client_address = ("serial", "server")
else:
Log.warning("Unable to get information about transport {}", transport)
self.transport = transport # pylint: disable=attribute-defined-outside-init
self.transport = transport
self.running = True
self.framer = ( # pylint: disable=attribute-defined-outside-init
self.server.framer(
self.server.decoder,
client=None,
)
self.framer = self.server.framer(
self.server.decoder,
client=None,
)
self.server.active_connections[self.client_address] = self

Expand Down Expand Up @@ -267,13 +275,15 @@ def execute(self, request, *addr):
response, skip_encoding = self.server.response_manipulator(response)
self.send(response, *addr, skip_encoding=skip_encoding)

def send(self, message, *addr, **kwargs):
def send(self, message, *addr, **kwargs): # pylint: disable=arguments-differ
"""Send message."""

def __send(msg, *addr):
Log.debug("send: [{}]- {}", message, msg, ":b2a")
if addr == (None,):
self._send_(msg)
self.transport.write(msg)
if self.server.handle_local_echo is True:
self._sent = msg
else:
self.transport.sendto(msg, *addr)

Expand All @@ -286,20 +296,6 @@ def __send(msg, *addr):
else:
Log.debug("Skipping sending response!!")

# ----------------------------------------------------------------------- #
# Derived class implementations
# ----------------------------------------------------------------------- #

def _send_(self, data): # pragma: no cover
"""Send a request (string) to the network.
:param data: The unencoded modbus response
:raises NotImplementedException:
"""
self.transport.write(data)
if self.server.handle_local_echo is True:
self._sent = data

async def _recv_(self): # pragma: no cover
"""Receive data from the network."""
try:
Expand Down Expand Up @@ -390,8 +386,6 @@ def __init__(
self.context = context or ModbusServerContext()
self.control = ModbusControlBlock()
self.path = path
self.handler = ModbusServerRequestHandler
self.handler.server = self
self.ignore_missing_slaves = kwargs.get("ignore_missing_slaves", False)
self.broadcast_enable = kwargs.get("broadcast_enable", False)
self.response_manipulator = kwargs.get("response_manipulator", None)
Expand All @@ -412,8 +406,10 @@ async def serve_forever(self):
"""Start endless loop."""
if self.server is None:
try:
handler = ModbusServerRequestHandler
handler.server = self
self.server = await self.loop.create_unix_server(
lambda: self.handler(self),
lambda: handler(self),
self.path,
)
self.serving.set_result(True)
Expand Down Expand Up @@ -494,8 +490,6 @@ def __init__(
self.context = context or ModbusServerContext()
self.control = ModbusControlBlock()
self.address = address or ("", 502)
self.handler = ModbusServerRequestHandler
self.handler.server = self
self.ignore_missing_slaves = kwargs.get("ignore_missing_slaves", False)
self.broadcast_enable = kwargs.get("broadcast_enable", False)
self.response_manipulator = kwargs.get("response_manipulator", None)
Expand All @@ -519,8 +513,10 @@ def __init__(
async def serve_forever(self):
"""Start endless loop."""
if self.server is None:
handler = ModbusServerRequestHandler
handler.server = self
self.server = await self.loop.create_server(
lambda: self.handler(self),
lambda: handler(self),
*self.address,
**self.factory_parms,
)
Expand Down Expand Up @@ -669,7 +665,6 @@ def __init__(
self.context = context or ModbusServerContext()
self.control = ModbusControlBlock()
self.address = address or ("", 502)
self.handler = ModbusServerRequestHandler
self.ignore_missing_slaves = kwargs.get("ignore_missing_slaves", False)
self.broadcast_enable = kwargs.get("broadcast_enable", False)
self.response_manipulator = kwargs.get("response_manipulator", None)
Expand All @@ -694,8 +689,10 @@ async def serve_forever(self):
"""Start endless loop."""
if self.protocol is None:
try:
handler = ModbusServerRequestHandler
handler.server = self
self.protocol, self.endpoint = await self.loop.create_datagram_endpoint(
lambda: self.handler(self),
lambda: handler(self),
**self.factory_parms,
)
except asyncio.exceptions.CancelledError:
Expand Down Expand Up @@ -782,7 +779,6 @@ def __init__(
self.auto_reconnect = kwargs.get("auto_reconnect", False)
self.reconnect_delay = kwargs.get("reconnect_delay", 2)
self.reconnecting_task = None
self.handler = kwargs.get("handler") or ModbusServerRequestHandler
self.framer = framer or ModbusRtuFramer
self.decoder = ServerDecoder()
self.context = context or ModbusServerContext()
Expand Down Expand Up @@ -818,9 +814,11 @@ async def _connect(self):
if self.device.startswith("socket:"):
return
try:
handler = ModbusServerRequestHandler
handler.server = self
self.transport, self.protocol = await create_serial_connection(
self.loop,
lambda: self.handler(self),
lambda: handler(self),
self.device,
baudrate=self.baudrate,
bytesize=self.bytesize,
Expand Down Expand Up @@ -889,8 +887,10 @@ async def serve_forever(self):
# Socket server means listen so start a socket server
parts = self.device[9:].split(":")
host_addr = (parts[0], int(parts[1]))
handler = ModbusServerRequestHandler
handler.server = self
self.server = await self.loop.create_server(
lambda: self.handler(self),
lambda: handler(self),
*host_addr,
reuse_address=True,
start_serving=True,
Expand Down
115 changes: 0 additions & 115 deletions pymodbus/transport/nullmodem.py

This file was deleted.

Loading

0 comments on commit a6b135a

Please sign in to comment.