|
5 | 5 |
|
6 | 6 | import struct |
7 | 7 | import socket |
| 8 | +import time |
8 | 9 | from threading import RLock |
9 | 10 | from functools import partial |
10 | 11 |
|
@@ -62,7 +63,9 @@ def __init__(self, client, **kwargs): |
62 | 63 | """ |
63 | 64 | self.tid = Defaults.TransactionId |
64 | 65 | self.client = client |
| 66 | + self.backoff = kwargs.get('backoff', Defaults.Backoff) or 0.3 |
65 | 67 | self.retry_on_empty = kwargs.get('retry_on_empty', Defaults.RetryOnEmpty) |
| 68 | + self.retry_on_invalid = kwargs.get('retry_on_invalid', Defaults.RetryOnInvalid) |
66 | 69 | self.retries = kwargs.get('retries', Defaults.Retries) or 1 |
67 | 70 | self._transaction_lock = RLock() |
68 | 71 | self._no_response_devices = [] |
@@ -146,34 +149,42 @@ def execute(self, request): |
146 | 149 | full = True |
147 | 150 | if not expected_response_length: |
148 | 151 | expected_response_length = Defaults.ReadSize |
149 | | - response, last_exception = self._transact( |
150 | | - request, |
151 | | - expected_response_length, |
152 | | - full=full, |
153 | | - broadcast=broadcast |
154 | | - ) |
155 | | - if not response and ( |
156 | | - request.unit_id not in self._no_response_devices): |
157 | | - self._no_response_devices.append(request.unit_id) |
158 | | - elif request.unit_id in self._no_response_devices and response: |
159 | | - self._no_response_devices.remove(request.unit_id) |
160 | | - if not response and self.retry_on_empty and retries: |
161 | | - while retries > 0: |
162 | | - if hasattr(self.client, "state"): |
163 | | - _logger.debug("RESETTING Transaction state to " |
164 | | - "'IDLE' for retry") |
165 | | - self.client.state = ModbusTransactionState.IDLE |
166 | | - _logger.debug("Retry on empty - {}".format(retries)) |
167 | | - response, last_exception = self._transact( |
168 | | - request, |
169 | | - expected_response_length |
170 | | - ) |
171 | | - if not response: |
172 | | - retries -= 1 |
173 | | - continue |
174 | | - # Remove entry |
| 152 | + retries += 1 |
| 153 | + while retries > 0: |
| 154 | + response, last_exception = self._transact( |
| 155 | + request, |
| 156 | + expected_response_length, |
| 157 | + full=full, |
| 158 | + broadcast=broadcast |
| 159 | + ) |
| 160 | + if not response and ( |
| 161 | + request.unit_id not in self._no_response_devices): |
| 162 | + self._no_response_devices.append(request.unit_id) |
| 163 | + elif request.unit_id in self._no_response_devices and response: |
175 | 164 | self._no_response_devices.remove(request.unit_id) |
| 165 | + if not response and self.retry_on_empty: |
| 166 | + _logger.debug("Retry on empty - {}".format(retries)) |
| 167 | + elif not response: |
| 168 | + break |
| 169 | + if not self.retry_on_invalid: |
176 | 170 | break |
| 171 | + mbap = self.client.framer.decode_data(response) |
| 172 | + if (mbap.get('unit') == request.unit_id): |
| 173 | + break |
| 174 | + if ('length' in mbap and expected_response_length and |
| 175 | + mbap.get('length') == expected_response_length): |
| 176 | + break |
| 177 | + _logger.debug("Retry on invalid - {}".format(retries)) |
| 178 | + if hasattr(self.client, "state"): |
| 179 | + _logger.debug("RESETTING Transaction state to 'IDLE' for retry") |
| 180 | + self.client.state = ModbusTransactionState.IDLE |
| 181 | + if self.backoff: |
| 182 | + delay = 2 ** (self.retries - retries) * self.backoff |
| 183 | + time.sleep(delay) |
| 184 | + _logger.debug("Sleeping {}".format(delay)) |
| 185 | + full = False |
| 186 | + broadcast = False |
| 187 | + retries -= 1 |
177 | 188 | addTransaction = partial(self.addTransaction, |
178 | 189 | tid=request.transaction_id) |
179 | 190 | self.client.framer.processIncomingPacket(response, |
|
0 commit comments