@@ -27,13 +27,44 @@ def __init__(self, simulator, register_type: str, address_range: tuple):
2727 """
2828 self .simulator = simulator
2929 self .register_type = register_type
30+ self .address_range = address_range
3031
3132 # Initialize with zeros
3233 initial_values = [0 ] * address_range [1 ]
33- super ().__init__ (address_range [0 ], initial_values )
34+ super ().__init__ (0 , initial_values )
35+ logger .info (f"DynamicModbusDataBlock initialized: type={ register_type } , address=0, count={ address_range [1 ]} " )
36+
37+ def update_from_simulator (self ):
38+ """Update internal storage from simulator values."""
39+ # Get registers from model
40+ if self .register_type == 'input' :
41+ registers = self .simulator .model .get_input_registers ()
42+ else :
43+ registers = self .simulator .model .get_holding_registers ()
3444
35- def getValues (self , address , count = 1 ):
36- """Get register values from simulator.
45+ # Update each mapped register
46+ for addr , reg_def in registers .items ():
47+ value = self .simulator .get_register_value (self .register_type , addr )
48+ if value is not None :
49+ # WORKAROUND: pymodbus 3.x has an off-by-one quirk where reading address N
50+ # returns the value stored at address N+1. To compensate, store value for
51+ # register N at address N-1.
52+ store_addr = addr - 1
53+ if store_addr < 0 :
54+ continue # Skip register 0
55+
56+ # Debug logging for key registers
57+ if addr in [38 , 39 , 1011 , 1012 , 1013 , 1014 ]:
58+ logger .info (f" Setting register { addr } to { value } (storing at { store_addr } )" )
59+ # Use parent's setValues to update internal storage
60+ result = super ().setValues (store_addr , [value ])
61+ if addr in [38 , 39 , 1011 , 1012 , 1013 , 1014 ]:
62+ # Verify it was set correctly
63+ verify = super ().getValues (store_addr , 1 )
64+ logger .info (f" Verify: getValues({ store_addr } ) returns { verify } " )
65+
66+ def _get_values_from_simulator (self , address , count ):
67+ """Helper to get values from simulator.
3768
3869 Args:
3970 address: Starting register address
@@ -51,6 +82,44 @@ def getValues(self, address, count=1):
5182 values .append (value )
5283 return values
5384
85+ def getValues (self , address , count = 1 ):
86+ """Get register values from simulator (sync).
87+
88+ Args:
89+ address: Starting register address
90+ count: Number of registers to read
91+
92+ Returns:
93+ List of register values
94+ """
95+ return self ._get_values_from_simulator (address , count )
96+
97+ async def async_getValues (self , address , count = 1 ):
98+ """Get register values from simulator (async).
99+
100+ Args:
101+ address: Starting register address
102+ count: Number of registers to read
103+
104+ Returns:
105+ List of register values
106+ """
107+ return self ._get_values_from_simulator (address , count )
108+
109+ def validate (self , address , count = 1 ):
110+ """Validate the request and return the address range.
111+
112+ Args:
113+ address: Starting address
114+ count: Number of registers
115+
116+ Returns:
117+ Validation result
118+ """
119+ # Let the parent handle validation
120+ result = super ().validate (address , count )
121+ return result
122+
54123 def setValues (self , address , values ):
55124 """Set register values (for holding registers).
56125
@@ -101,8 +170,8 @@ def __init__(self, simulator, port: int = 502, slave_id: int = 1):
101170 holding_range = (0 , 100 )
102171
103172 # Create dynamic data blocks
104- input_block = DynamicModbusDataBlock (simulator , 'input' , input_range )
105- holding_block = DynamicModbusDataBlock (simulator , 'holding' , holding_range )
173+ self . input_block = DynamicModbusDataBlock (simulator , 'input' , input_range )
174+ self . holding_block = DynamicModbusDataBlock (simulator , 'holding' , holding_range )
106175
107176 # Discrete and coil blocks (not used, but required)
108177 discrete_block = ModbusSequentialDataBlock (0 , [0 ] * 100 )
@@ -112,10 +181,14 @@ def __init__(self, simulator, port: int = 502, slave_id: int = 1):
112181 self .device_context = ModbusDeviceContext (
113182 di = discrete_block , # Discrete Inputs
114183 co = coil_block , # Coils
115- hr = holding_block , # Holding Registers
116- ir = input_block # Input Registers
184+ hr = self . holding_block , # Holding Registers
185+ ir = self . input_block # Input Registers
117186 )
118187
188+ # Initial update
189+ self .input_block .update_from_simulator ()
190+ self .holding_block .update_from_simulator ()
191+
119192 # Create server context
120193 self .server_context = ModbusServerContext (
121194 devices = {slave_id : self .device_context },
@@ -141,6 +214,9 @@ def update_callback():
141214 """Callback to update simulator values."""
142215 if self .running :
143216 self .simulator .update ()
217+ # Update Modbus register storage
218+ self .input_block .update_from_simulator ()
219+ self .holding_block .update_from_simulator ()
144220 threading .Timer (2.0 , update_callback ).start ()
145221
146222 # Start update timer
0 commit comments