Skip to content

Commit cdcfc6f

Browse files
authored
Slave=0 will return first response, used to identify device address. (#2298)
1 parent 3190a5a commit cdcfc6f

File tree

3 files changed

+68
-101
lines changed

3 files changed

+68
-101
lines changed

pymodbus/transaction.py

Lines changed: 68 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -214,82 +214,78 @@ def execute(self, request: ModbusRequest): # noqa: C901
214214
):
215215
Log.debug("Clearing current Frame: - {}", _buffer)
216216
self.client.framer.resetFrame()
217-
if broadcast := not request.slave_id:
218-
self._transact(request, None, broadcast=True)
219-
response = b"Broadcast write sent - no response expected"
217+
broadcast = not request.slave_id
218+
expected_response_length = None
219+
if not isinstance(self.client.framer, ModbusSocketFramer):
220+
if hasattr(request, "get_response_pdu_size"):
221+
response_pdu_size = request.get_response_pdu_size()
222+
if isinstance(self.client.framer, ModbusAsciiFramer):
223+
response_pdu_size *= 2
224+
if response_pdu_size:
225+
expected_response_length = (
226+
self._calculate_response_length(response_pdu_size)
227+
)
228+
if ( # pylint: disable=simplifiable-if-statement
229+
request.slave_id in self._no_response_devices
230+
):
231+
full = True
220232
else:
221-
expected_response_length = None
222-
if not isinstance(self.client.framer, ModbusSocketFramer):
223-
if hasattr(request, "get_response_pdu_size"):
224-
response_pdu_size = request.get_response_pdu_size()
225-
if isinstance(self.client.framer, ModbusAsciiFramer):
226-
response_pdu_size *= 2
227-
if response_pdu_size:
228-
expected_response_length = (
229-
self._calculate_response_length(response_pdu_size)
230-
)
231-
if ( # pylint: disable=simplifiable-if-statement
232-
request.slave_id in self._no_response_devices
233-
):
234-
full = True
235-
else:
236-
full = False
237-
is_udp = False
238-
if self.client.comm_params.comm_type == CommType.UDP:
239-
is_udp = True
240-
full = True
241-
if not expected_response_length:
242-
expected_response_length = 1024
243-
response, last_exception = self._transact(
244-
request,
245-
expected_response_length,
246-
full=full,
247-
broadcast=broadcast,
233+
full = False
234+
is_udp = False
235+
if self.client.comm_params.comm_type == CommType.UDP:
236+
is_udp = True
237+
full = True
238+
if not expected_response_length:
239+
expected_response_length = 1024
240+
response, last_exception = self._transact(
241+
request,
242+
expected_response_length,
243+
full=full,
244+
broadcast=broadcast,
245+
)
246+
while retries > 0:
247+
valid_response = self._validate_response(
248+
request, response, expected_response_length,
249+
is_udp=is_udp
248250
)
249-
while retries > 0:
250-
valid_response = self._validate_response(
251-
request, response, expected_response_length,
252-
is_udp=is_udp
253-
)
254-
if valid_response:
255-
if (
256-
request.slave_id in self._no_response_devices
257-
and response
258-
):
259-
self._no_response_devices.remove(request.slave_id)
260-
Log.debug("Got response!!!")
261-
break
262-
if not response:
263-
if request.slave_id not in self._no_response_devices:
264-
self._no_response_devices.append(request.slave_id)
265-
# No response received and retries not enabled
251+
if valid_response:
252+
if (
253+
request.slave_id in self._no_response_devices
254+
and response
255+
):
256+
self._no_response_devices.remove(request.slave_id)
257+
Log.debug("Got response!!!")
266258
break
267-
self.client.framer.processIncomingPacket(
268-
response,
269-
self.addTransaction,
270-
request.slave_id,
271-
tid=request.transaction_id,
272-
)
273-
if not (response := self.getTransaction(request.transaction_id)):
274-
if len(self.transactions):
275-
response = self.getTransaction(tid=0)
276-
else:
277-
last_exception = last_exception or (
278-
"No Response received from the remote slave"
279-
"/Unable to decode response"
280-
)
281-
response = ModbusIOException(
282-
last_exception, request.function_code # type: ignore[assignment]
283-
)
284-
self.client.close()
285-
if hasattr(self.client, "state"):
286-
Log.debug(
287-
"Changing transaction state from "
288-
'"PROCESSING REPLY" to '
289-
'"TRANSACTION_COMPLETE"'
259+
if not response:
260+
if request.slave_id not in self._no_response_devices:
261+
self._no_response_devices.append(request.slave_id)
262+
# No response received and retries not enabled
263+
break
264+
self.client.framer.processIncomingPacket(
265+
response,
266+
self.addTransaction,
267+
request.slave_id,
268+
tid=request.transaction_id,
269+
)
270+
if not (response := self.getTransaction(request.transaction_id)):
271+
if len(self.transactions):
272+
response = self.getTransaction(tid=0)
273+
else:
274+
last_exception = last_exception or (
275+
"No Response received from the remote slave"
276+
"/Unable to decode response"
290277
)
291-
self.client.state = ModbusTransactionState.TRANSACTION_COMPLETE
292-
278+
response = ModbusIOException(
279+
last_exception, request.function_code
280+
)
281+
self.client.close()
282+
if hasattr(self.client, "state"):
283+
Log.debug(
284+
"Changing transaction state from "
285+
'"PROCESSING REPLY" to '
286+
'"TRANSACTION_COMPLETE"'
287+
)
288+
self.client.state = ModbusTransactionState.TRANSACTION_COMPLETE
293289
return response
294290
except ModbusIOException as exc:
295291
# Handle decode errors in processIncomingPacket method

test/framers/test_tbc_transaction.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -160,21 +160,6 @@ def test_execute(self):
160160
)
161161
assert isinstance(trans.execute(request), ModbusIOException)
162162

163-
# Broadcast
164-
request.slave_id = 0
165-
response = trans.execute(request)
166-
assert response == b"Broadcast write sent - no response expected"
167-
168-
# Broadcast w/ Local echo
169-
client.comm_params.handle_local_echo = True
170-
recv = mock.MagicMock(return_value=b"deadbeef")
171-
trans._recv = recv # pylint: disable=protected-access
172-
request.slave_id = 0
173-
response = trans.execute(request)
174-
assert response == b"Broadcast write sent - no response expected"
175-
recv.assert_called_once_with(8, False)
176-
client.comm_params.handle_local_echo = False
177-
178163
def test_transaction_manager_tid(self):
179164
"""Test the transaction manager TID."""
180165
for tid in range(1, self._manager.getNextTID() + 10):

test/test_transaction.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -161,20 +161,6 @@ def test_execute(self, mock_get_transaction, mock_recv):
161161
)
162162
assert isinstance(trans.execute(request), ModbusIOException)
163163

164-
# Broadcast
165-
request.slave_id = 0
166-
response = trans.execute(request)
167-
assert response == b"Broadcast write sent - no response expected"
168-
169-
# Broadcast w/ Local echo
170-
client.comm_params.handle_local_echo = True
171-
mock_recv.reset_mock(return_value=b"deadbeef")
172-
request.slave_id = 0
173-
response = trans.execute(request)
174-
assert response == b"Broadcast write sent - no response expected"
175-
mock_recv.assert_called_once_with(8, False)
176-
client.comm_params.handle_local_echo = False
177-
178164
def test_transaction_manager_tid(self):
179165
"""Test the transaction manager TID."""
180166
for tid in range(1, self._manager.getNextTID() + 10):

0 commit comments

Comments
 (0)