diff --git a/pymodbus/server/base.py b/pymodbus/server/base.py index 2f5e02bb2..9065abadd 100644 --- a/pymodbus/server/base.py +++ b/pymodbus/server/base.py @@ -10,6 +10,8 @@ from ..logging import Log from ..pdu import DecodePDU, ModbusPDU from ..pdu.device import ModbusControlBlock, ModbusDeviceIdentification +from ..simulator import SimDevice +from ..simulator.simcore import SimCore from ..transport import CommParams, ModbusProtocol from .requesthandler import ServerRequestHandler @@ -22,7 +24,7 @@ class ModbusBaseServer(ModbusProtocol): def __init__( # pylint: disable=too-many-arguments self, params: CommParams, - context: ModbusServerContext | None, + context: ModbusServerContext | SimDevice | list[SimDevice], ignore_missing_devices: bool, broadcast_enable: bool, identity: ModbusDeviceIdentification | None, @@ -42,7 +44,11 @@ def __init__( # pylint: disable=too-many-arguments if custom_pdu: for func in custom_pdu: self.decoder.register(func) - self.context = context or ModbusServerContext() + self.context: ModbusServerContext | SimCore + if isinstance(context, ModbusServerContext): + self.context = context + else: + self.context = SimCore(context) self.control = ModbusControlBlock() self.ignore_missing_devices = ignore_missing_devices self.broadcast_enable = broadcast_enable diff --git a/pymodbus/server/server.py b/pymodbus/server/server.py index a2550eaf0..223f24bd6 100644 --- a/pymodbus/server/server.py +++ b/pymodbus/server/server.py @@ -7,6 +7,7 @@ from ..framer import FramerType from ..pdu import ModbusPDU from ..pdu.device import ModbusDeviceIdentification +from ..simulator import SimDevice from ..transport import CommParams, CommType from .base import ModbusBaseServer @@ -20,7 +21,7 @@ class ModbusTcpServer(ModbusBaseServer): def __init__( # pylint: disable=too-many-arguments self, - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], *, framer=FramerType.SOCKET, identity: ModbusDeviceIdentification | None = None, @@ -84,7 +85,7 @@ class ModbusTlsServer(ModbusTcpServer): def __init__( # pylint: disable=too-many-arguments self, - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], *, framer=FramerType.TLS, identity: ModbusDeviceIdentification | None = None, @@ -155,7 +156,7 @@ class ModbusUdpServer(ModbusBaseServer): def __init__( # pylint: disable=too-many-arguments self, - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], *, framer=FramerType.SOCKET, identity: ModbusDeviceIdentification | None = None, @@ -216,7 +217,7 @@ class ModbusSerialServer(ModbusBaseServer): def __init__( self, - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], *, framer: FramerType = FramerType.RTU, ignore_missing_devices: bool = False, diff --git a/pymodbus/server/startstop.py b/pymodbus/server/startstop.py index 79a522584..2cf900cf9 100644 --- a/pymodbus/server/startstop.py +++ b/pymodbus/server/startstop.py @@ -5,6 +5,7 @@ from time import sleep from ..datastore import ModbusServerContext +from ..simulator import SimDevice from .base import ModbusBaseServer from .server import ( ModbusSerialServer, @@ -15,7 +16,7 @@ async def StartAsyncTcpServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs, ) -> None: """Start and run a tcp modbus server. @@ -32,7 +33,7 @@ async def StartAsyncTcpServer( def StartTcpServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs ) -> None: """Start and run a modbus TCP server. @@ -49,7 +50,7 @@ def StartTcpServer( async def StartAsyncTlsServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs, ) -> None: """Start and run a tls modbus server. @@ -66,7 +67,7 @@ async def StartAsyncTlsServer( def StartTlsServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs ) -> None: """Start and run a modbus TLS server. @@ -83,7 +84,7 @@ def StartTlsServer( async def StartAsyncUdpServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs, ) -> None: """Start and run a udp modbus server. @@ -100,7 +101,7 @@ async def StartAsyncUdpServer( def StartUdpServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs ) -> None: """Start and run a modbus UDP server. @@ -117,7 +118,7 @@ def StartUdpServer( async def StartAsyncSerialServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs, ) -> None: """Start and run a serial modbus server. @@ -134,7 +135,7 @@ async def StartAsyncSerialServer( def StartSerialServer( - context: ModbusServerContext, + context: ModbusServerContext | SimDevice | list[SimDevice], **kwargs ) -> None: """Start and run a modbus serial server. diff --git a/pymodbus/simulator/simcore.py b/pymodbus/simulator/simcore.py index 304570eb6..77945327b 100644 --- a/pymodbus/simulator/simcore.py +++ b/pymodbus/simulator/simcore.py @@ -5,6 +5,7 @@ from __future__ import annotations from ..constants import ExcCodes +from ..pdu.pdu import unpack_bitstring from .simdevice import SimDevice, SimRegs @@ -22,10 +23,15 @@ class Runtime: for i in (1, 5, 15)]) - def __convert_to_bit(self, block: SimRegs): + @classmethod + def convert_to_bit(cls, block: SimRegs) -> SimRegs: """Convert registers to bits.""" - new_flags = block[1] - new_registers = block[2] + new_registers: list[int] = [] + for entry in block[2]: + bool_list = unpack_bitstring(entry.to_bytes(2, byteorder="big")) + for x in bool_list: + new_registers.append(1 if x else 0) + new_flags: list[int] = [block[1][0]]*len(new_registers) return (block[0], new_flags, new_registers) def __init__(self, device: SimDevice): @@ -39,8 +45,8 @@ def __init__(self, device: SimDevice): return self.shared = False self.block: dict[str, SimRegs] = { - "c": self.__convert_to_bit(build["c"]), - "d": self.__convert_to_bit(build["d"]), + "c": self.convert_to_bit(build["c"]), + "d": self.convert_to_bit(build["d"]), "h": build["h"], "i": build["i"], } diff --git a/test/client/test_client_sync.py b/test/client/test_client_sync.py index f2bfacc9f..0b7019d18 100755 --- a/test/client/test_client_sync.py +++ b/test/client/test_client_sync.py @@ -31,7 +31,9 @@ class TestSyncClientUdp: def test_basic_syn_udp_bind(self): """Test the basic methods for the udp sync client.""" - ModbusUdpClient("127.0.0.1", source_address=('', 4096)) + client = ModbusUdpClient("127.0.0.1", source_address=('', 4096)) + client.connect() + def test_basic_syn_udp_client(self): """Test the basic methods for the udp sync client.""" diff --git a/test/server/test_base.py b/test/server/test_base.py index f027936cd..4bec6dcd1 100755 --- a/test/server/test_base.py +++ b/test/server/test_base.py @@ -3,8 +3,10 @@ import pytest +from pymodbus.datastore import ModbusServerContext from pymodbus.pdu import ReadHoldingRegistersRequest from pymodbus.server import ModbusBaseServer +from pymodbus.simulator import SimData, SimDevice from pymodbus.transport import CommParams, CommType @@ -22,7 +24,7 @@ async def baseserver(self): reconnect_delay_max=0.0, timeout_connect=0.0, ), - None, + ModbusServerContext(), False, False, None, @@ -37,6 +39,27 @@ async def baseserver(self): async def test_base(self, baseserver): """Test __init__.""" + async def test_base_simcore(self): + """Test __init___ with SimCore.""" + ModbusBaseServer( + CommParams( + comm_type=CommType.TCP, + comm_name="server_listener", + reconnect_delay=0.0, + reconnect_delay_max=0.0, + timeout_connect=0.0, + ), + SimDevice(0, SimData(0)), + False, + False, + None, + "socket", + None, + None, + None, + [ReadHoldingRegistersRequest], + ) + async def test_base_serve_forever1(self, baseserver): """Test serve_forever.""" baseserver.listen = mock.AsyncMock(return_value=None) diff --git a/test/simulator/test_simcore.py b/test/simulator/test_simcore.py index 9f9be6820..e895079d2 100644 --- a/test/simulator/test_simcore.py +++ b/test/simulator/test_simcore.py @@ -48,3 +48,13 @@ async def test_simdcore_set(self, kwargs): """Test that simdata can be objects.""" core = SimCore(devices=SimDevice(0, simdata=self.simdata2)) await core.async_setValues(**kwargs) + + @pytest.mark.parametrize(("block", "expect"), [ + ((3, [1], [0xffff]), (3, [1]*16, [1]*16)), + ((3, [1], [0x0000]), (3, [1]*16, [0]*16)), + ((3, [1], [0xffff, 0xffff]), (3, [1]*32, [1]*32)), + ]) + async def test_simdcore_convert_bit(self, block, expect): + """Test that simdata can be objects.""" + result = SimCore.Runtime.convert_to_bit(block) + assert result == expect