diff --git a/umodbus/functions.py b/umodbus/functions.py index 4db3cec..f03243b 100644 --- a/umodbus/functions.py +++ b/umodbus/functions.py @@ -75,7 +75,7 @@ from umodbus.exceptions import (error_code_to_exception_map, IllegalDataValueError, IllegalFunctionError, IllegalDataAddressError) -from umodbus.utils import memoize, get_function_code_from_request_pdu +from umodbus.utils import get_function_code_from_request_pdu # Function related to data access. READ_COILS = 1 @@ -111,10 +111,10 @@ def pdu_to_function_code_or_raise_error(resp_pdu): :return: Subclass of :class:`ModbusFunction` matching the response. :raises ModbusError: When response contains error code. """ - function_code = struct.unpack('>B', resp_pdu[0:1])[0] + function_code = resp_pdu[0] if function_code not in function_code_to_function_map.keys(): - error_code = struct.unpack('>B', resp_pdu[1:2])[0] + error_code = resp_pdu[1] raise error_code_to_exception_map[error_code] return function_code @@ -140,7 +140,6 @@ def create_function_from_response_pdu(resp_pdu, req_pdu=None): return function.create_from_response_pdu(resp_pdu) -@memoize def create_function_from_request_pdu(pdu): """ Return function instance, based on request PDU. @@ -317,12 +316,7 @@ def create_response_pdu(self, data): reduce(lambda a, b: (a << 1) + b, list(reversed(byte))) log.debug('Reduced single bit data to {0}.'.format(bytes_)) - # The first 2 B's of the format encode the function code (1 byte) and - # the length (1 byte) of the following byte series. Followed by # a B - # for every byte in the series of bytes. 3 lead to the format '>BBB' - # and 257 lead to the format '>BBBB'. - fmt = '>BB' + self.format_character * len(bytes_) - return struct.pack(fmt, self.function_code, len(bytes_), *bytes_) + return bytes([self.function_code, len(bytes_), *bytes_]) @classmethod def create_from_response_pdu(cls, resp_pdu, req_pdu): @@ -336,10 +330,8 @@ def create_from_response_pdu(cls, resp_pdu, req_pdu): """ read_coils = cls() read_coils.quantity = struct.unpack('>H', req_pdu[-2:])[0] - byte_count = struct.unpack('>B', resp_pdu[1:2])[0] - - fmt = '>' + ('B' * byte_count) - bytes_ = struct.unpack(fmt, resp_pdu[2:]) + byte_count = resp_pdu[1] + bytes_ = resp_pdu[2:] data = list() @@ -525,12 +517,7 @@ def create_response_pdu(self, data): reduce(lambda a, b: (a << 1) + b, list(reversed(byte))) log.debug('Reduced single bit data to {0}.'.format(bytes_)) - # The first 2 B's of the format encode the function code (1 byte) and - # the length (1 byte) of the following byte series. Followed by # a B - # for every byte in the series of bytes. 3 lead to the format '>BBB' - # and 257 lead to the format '>BBBB'. - fmt = '>BB' + self.format_character * len(bytes_) - return struct.pack(fmt, self.function_code, len(bytes_), *bytes_) + return bytes([self.function_code, len(bytes_), *bytes_]) @classmethod def create_from_response_pdu(cls, resp_pdu, req_pdu): @@ -544,10 +531,8 @@ def create_from_response_pdu(cls, resp_pdu, req_pdu): """ read_discrete_inputs = cls() read_discrete_inputs.quantity = struct.unpack('>H', req_pdu[-2:])[0] - byte_count = struct.unpack('>B', resp_pdu[1:2])[0] - - fmt = '>' + ('B' * byte_count) - bytes_ = struct.unpack(fmt, resp_pdu[2:]) + byte_count = resp_pdu[1] + bytes_ = resp_pdu[2:] data = list() diff --git a/umodbus/route.py b/umodbus/route.py index 3765e87..538c67a 100644 --- a/umodbus/route.py +++ b/umodbus/route.py @@ -7,8 +7,11 @@ def add_rule(self, endpoint, slave_ids, function_codes, addresses): addresses)) def match(self, slave_id, function_code, address): + if not self._rules[0].match_slave_id(slave_id): + return False + for rule in self._rules: - if rule.match(slave_id, function_code, address): + if rule.match(function_code, address): return rule.endpoint @@ -19,9 +22,16 @@ def __init__(self, endpoint, slave_ids, function_codes, addresses): self.function_codes = function_codes self.addresses = addresses - def match(self, slave_id, function_code, address): + def match(self, function_code, address): # A constraint of None matches any value matches = lambda values, v: values is None or v in values - return matches(self.slave_ids, slave_id) and \ - matches(self.function_codes, function_code) and \ + + return matches(self.function_codes, function_code) and \ matches(self.addresses, address) + + def match_slave_id(self, slave_id): + matches = lambda values, v: values is None or v in values + + if matches(self.slave_ids, slave_id): + return True + return False diff --git a/umodbus/server/__init__.py b/umodbus/server/__init__.py index f9d4093..faa7091 100644 --- a/umodbus/server/__init__.py +++ b/umodbus/server/__init__.py @@ -63,6 +63,8 @@ def process(self, request_adu): request_pdu = self.get_request_pdu(request_adu) response_pdu = self.execute_route(meta_data, request_pdu) + if response_pdu is False: + return False response_adu = self.create_response_adu(meta_data, response_pdu) return response_adu @@ -80,6 +82,9 @@ def execute_route(self, meta_data, request_pdu): function = create_function_from_request_pdu(request_pdu) results =\ function.execute(meta_data['unit_id'], self.server.route_map) + # Result is False if request SlaveId do not match modbus server SlaveId + if results is False: + return False try: # ReadFunction's use results of callbacks to build response diff --git a/umodbus/server/serial/__init__.py b/umodbus/server/serial/__init__.py index e820919..764c5dc 100644 --- a/umodbus/server/serial/__init__.py +++ b/umodbus/server/serial/__init__.py @@ -81,6 +81,8 @@ def process(self, request_adu): request_pdu = self.get_request_pdu(request_adu) response_pdu = self.execute_route(meta_data, request_pdu) + if response_pdu is False: + return False response_adu = self.create_response_adu(meta_data, response_pdu) return response_adu @@ -98,7 +100,8 @@ def execute_route(self, meta_data, request_pdu): function = create_function_from_request_pdu(request_pdu) results =\ function.execute(meta_data['unit_id'], self.route_map) - + if results is False: + return False try: # ReadFunction's use results of callbacks to build response # PDU... diff --git a/umodbus/server/serial/rtu.py b/umodbus/server/serial/rtu.py index 73e79ff..e7c25e5 100644 --- a/umodbus/server/serial/rtu.py +++ b/umodbus/server/serial/rtu.py @@ -55,7 +55,8 @@ def serve_once(self): raise ValueError response_adu = self.process(request_adu) - self.respond(response_adu) + if response_adu: + self.respond(response_adu) def process(self, request_adu): """ Process request ADU and return response.