Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix validate and setValues in RemoteSlaveContext #1599

Merged
merged 14 commits into from
Jun 18, 2023
5 changes: 5 additions & 0 deletions pymodbus/bit_read_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.pdu import ModbusRequest, ModbusResponse
from pymodbus.utilities import pack_bitstring, unpack_bitstring
from pymodbus.pdu import ExceptionResponse


class ReadBitsRequestBase(ModbusRequest):
Expand Down Expand Up @@ -171,6 +172,8 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
values = context.getValues(self.function_code, self.address, self.count)
if isinstance(values, ExceptionResponse):
return values
return ReadCoilsResponse(values)


Expand Down Expand Up @@ -237,6 +240,8 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
values = context.getValues(self.function_code, self.address, self.count)
if isinstance(values, ExceptionResponse):
return values
return ReadDiscreteInputsResponse(values)


Expand Down
11 changes: 9 additions & 2 deletions pymodbus/bit_write_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.pdu import ModbusRequest, ModbusResponse
from pymodbus.utilities import pack_bitstring, unpack_bitstring
from pymodbus.pdu import ExceptionResponse


# ---------------------------------------------------------------------------#
Expand Down Expand Up @@ -90,8 +91,12 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, 1):
return self.doException(merror.IllegalAddress)

context.setValues(self.function_code, self.address, [self.value])
result = context.setValues(self.function_code, self.address, [self.value])
if isinstance(result, ExceptionResponse):
return result
values = context.getValues(self.function_code, self.address, 1)
if isinstance(values, ExceptionResponse):
return values
return WriteSingleCoilResponse(self.address, values[0])

def get_response_pdu_size(self):
Expand Down Expand Up @@ -222,7 +227,9 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, count):
return self.doException(merror.IllegalAddress)

context.setValues(self.function_code, self.address, self.values)
result = context.setValues(self.function_code, self.address, self.values)
if isinstance(result, ExceptionResponse):
return result
return WriteMultipleCoilsResponse(self.address, count)

def __str__(self):
Expand Down
30 changes: 17 additions & 13 deletions pymodbus/datastore/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,37 @@ def reset(self):
raise NotImplementedException()

def validate(self, fc_as_hex, address, count=1):
# pylint: disable=unused-argument
"""Validate the request to make sure it is in range.

:param fc_as_hex: The function we are working with
:param address: The starting address
:param count: The number of values to test
:returns: True if the request in within range, False otherwise
"""
Log.debug("validate[{}] {}:{}", fc_as_hex, address, count)
group_fx = self.decode(fc_as_hex)
if fc_as_hex in self._write_fc:
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
else:
func_fc = self.__get_callbacks[group_fx]
self.result = func_fc(address, count)
return not self.result.isError()
return True

def getValues(self, fc_as_hex, _address, _count=1):
"""Get values from real call in validate"""
if fc_as_hex in self._write_fc:
return [0]
group_fx = self.decode(fc_as_hex)
func_fc = self.__get_callbacks[group_fx]
self.result = func_fc(_address, _count)
return self.__extract_result(self.decode(fc_as_hex), self.result)

def setValues(self, fc_as_hex, address, values):
"""Set the datastore with the supplied values.

Already done in validate
"""
"""Set the datastore with the supplied values."""
group_fx = self.decode(fc_as_hex)
if fc_as_hex in self._write_fc:
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
if fc_as_hex in {0x0F, 0x10}:
self.result = func_fc(address, values)
else:
self.result = func_fc(address, values[0])
if self.result.isError():
return self.result
return None

def __str__(self):
"""Return a string representation of the context.
Expand Down Expand Up @@ -113,7 +117,7 @@ def __build_mapping(self):
a, v, **kwargs
),
}
self._write_fc = (0x05, 0x06, 0x15, 0x16, 0x17)
self._write_fc = (0x05, 0x06, 0x0F, 0x10)

def __extract_result(self, fc_as_hex, result):
"""Extract the values out of a response.
Expand Down
10 changes: 9 additions & 1 deletion pymodbus/register_read_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from pymodbus.constants import Defaults
from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.pdu import ModbusRequest, ModbusResponse
from pymodbus.pdu import ExceptionResponse


class ReadRegistersRequestBase(ModbusRequest):
Expand Down Expand Up @@ -151,6 +152,9 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
values = context.getValues(self.function_code, self.address, self.count)
if isinstance(values, ExceptionResponse):
return values

return ReadHoldingRegistersResponse(values)


Expand Down Expand Up @@ -209,6 +213,8 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)
values = context.getValues(self.function_code, self.address, self.count)
if isinstance(values, ExceptionResponse):
return values
return ReadInputRegistersResponse(values)


Expand Down Expand Up @@ -324,7 +330,9 @@ def execute(self, context):
return self.doException(merror.IllegalAddress)
if not context.validate(self.function_code, self.read_address, self.read_count):
return self.doException(merror.IllegalAddress)
context.setValues(self.function_code, self.write_address, self.write_registers)
result = context.setValues(self.function_code, self.write_address, self.write_registers)
if isinstance(result, ExceptionResponse):
return result
registers = context.getValues(
self.function_code, self.read_address, self.read_count
)
Expand Down
15 changes: 12 additions & 3 deletions pymodbus/register_write_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from pymodbus.pdu import ModbusExceptions as merror
from pymodbus.pdu import ModbusRequest, ModbusResponse
from pymodbus.pdu import ExceptionResponse


class WriteSingleRegisterRequest(ModbusRequest):
Expand Down Expand Up @@ -68,7 +69,9 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, 1):
return self.doException(merror.IllegalAddress)

context.setValues(self.function_code, self.address, [self.value])
result = context.setValues(self.function_code, self.address, [self.value])
if isinstance(result, ExceptionResponse):
return result
values = context.getValues(self.function_code, self.address, 1)
return WriteSingleRegisterResponse(self.address, values[0])

Expand Down Expand Up @@ -211,7 +214,9 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, self.count):
return self.doException(merror.IllegalAddress)

context.setValues(self.function_code, self.address, self.values)
result = context.setValues(self.function_code, self.address, self.values)
if isinstance(result, ExceptionResponse):
return result
return WriteMultipleRegistersResponse(self.address, self.count)

def get_response_pdu_size(self):
Expand Down Expand Up @@ -330,8 +335,12 @@ def execute(self, context):
if not context.validate(self.function_code, self.address, 1):
return self.doException(merror.IllegalAddress)
values = context.getValues(self.function_code, self.address, 1)[0]
if isinstance(values, ExceptionResponse):
return values
values = (values & self.and_mask) | (self.or_mask & ~self.and_mask)
context.setValues(self.function_code, self.address, [values])
result = context.setValues(self.function_code, self.address, [values])
if isinstance(result, ExceptionResponse):
return result
return MaskWriteRegisterResponse(self.address, self.and_mask, self.or_mask)


Expand Down