Skip to content

Commit db153e7

Browse files
committed
1. REPL Improvements
2. Support Intercharframe timeout for Modbus RTU
1 parent 65c3baf commit db153e7

File tree

11 files changed

+285
-86
lines changed

11 files changed

+285
-86
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ test/__pycache__/
3636
/doc/html/
3737
/doc/_build/
3838
.pytest_cache/
39-
/.pymodhis
39+
**/.pymodhis

pymodbus/client/sync.py

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ def __exit__(self, klass, value, traceback):
124124
self.close()
125125

126126
def idle_time(self):
127+
"""
128+
Bus Idle Time to initiate next transaction
129+
:return: time stamp
130+
"""
127131
if self.last_frame_end is None or self.silent_interval is None:
128132
return 0
129133
return self.last_frame_end + self.silent_interval
@@ -286,11 +290,11 @@ def __repr__(self):
286290
"port={self.port}, timeout={self.timeout}>"
287291
).format(self.__class__.__name__, hex(id(self)), self=self)
288292

289-
290-
291293
# --------------------------------------------------------------------------- #
292294
# Modbus UDP Client Transport Implementation
293295
# --------------------------------------------------------------------------- #
296+
297+
294298
class ModbusUdpClient(BaseModbusClient):
295299
""" Implementation of a modbus udp client
296300
"""
@@ -386,10 +390,14 @@ def __repr__(self):
386390
# --------------------------------------------------------------------------- #
387391
# Modbus Serial Client Transport Implementation
388392
# --------------------------------------------------------------------------- #
393+
394+
389395
class ModbusSerialClient(BaseModbusClient):
390396
""" Implementation of a modbus serial client
391397
"""
392398
state = ModbusTransactionState.IDLE
399+
inter_char_timeout = 0
400+
silent_interval = 0
393401

394402
def __init__(self, method='ascii', **kwargs):
395403
""" Initialize a serial client instance
@@ -413,18 +421,21 @@ def __init__(self, method='ascii', **kwargs):
413421
BaseModbusClient.__init__(self, self.__implementation(method, self),
414422
**kwargs)
415423

416-
self.port = kwargs.get('port', 0)
417-
self.stopbits = kwargs.get('stopbits', Defaults.Stopbits)
418-
self.bytesize = kwargs.get('bytesize', Defaults.Bytesize)
419-
self.parity = kwargs.get('parity', Defaults.Parity)
420-
self.baudrate = kwargs.get('baudrate', Defaults.Baudrate)
421-
self.timeout = kwargs.get('timeout', Defaults.Timeout)
422-
self.last_frame_end = None
424+
self._port = kwargs.get('port', 0)
425+
self._stopbits = kwargs.get('stopbits', Defaults.Stopbits)
426+
self._bytesize = kwargs.get('bytesize', Defaults.Bytesize)
427+
self._parity = kwargs.get('parity', Defaults.Parity)
428+
self._baudrate = kwargs.get('baudrate', Defaults.Baudrate)
429+
self._timeout = kwargs.get('timeout', Defaults.Timeout)
430+
self.last_frame_end = 0
423431
if self.method == "rtu":
424-
if self.baudrate > 19200:
432+
if self._baudrate > 19200:
433+
self._t0 = self.inter_char_timeout = 750.0/1000000 #Micro
425434
self.silent_interval = 1.75 / 1000 # ms
426435
else:
427-
self.silent_interval = 3.5 * (1 + 8 + 2) / self.baudrate
436+
self._t0 = float((1 + 8 + 2)) / self._baudrate
437+
self.inter_char_timeout = 1.5 * self._t0
438+
self.silent_interval = 3.5 * self._t0
428439
self.silent_interval = round(self.silent_interval, 6)
429440

430441
@staticmethod
@@ -453,16 +464,17 @@ def connect(self):
453464
if self.socket:
454465
return True
455466
try:
456-
self.socket = serial.Serial(port=self.port,
457-
timeout=self.timeout,
458-
bytesize=self.bytesize,
459-
stopbits=self.stopbits,
460-
baudrate=self.baudrate,
461-
parity=self.parity)
467+
self.socket = serial.Serial(port=self._port,
468+
timeout=self._timeout,
469+
bytesize=self._bytesize,
470+
stopbits=self._stopbits,
471+
baudrate=self._baudrate,
472+
parity=self._parity)
462473
except serial.SerialException as msg:
463474
_logger.error(msg)
464475
self.close()
465476
if self.method == "rtu":
477+
self.socket.interCharTimeout = self.inter_char_timeout
466478
self.last_frame_end = None
467479
return self.socket is not None
468480

@@ -512,8 +524,8 @@ def _send(self, request):
512524
return 0
513525

514526
def _wait_for_data(self):
515-
if self.timeout is not None and self.timeout != 0:
516-
condition = partial(lambda start, timeout: (time.time() - start) <= timeout, timeout=self.timeout)
527+
if self._timeout is not None and self._timeout != 0:
528+
condition = partial(lambda start, timeout: (time.time() - start) <= timeout, timeout=self._timeout)
517529
else:
518530
condition = partial(lambda dummy1, dummy2: True, dummy2=None)
519531
start = time.time()
@@ -550,7 +562,7 @@ def __str__(self):
550562
551563
:returns: The string representation
552564
"""
553-
return "ModbusSerialClient(%s baud[%s])" % (self.method, self.baudrate)
565+
return "ModbusSerialClient(%s baud[%s])" % (self.method, self._baudrate)
554566

555567
def __repr__(self):
556568
return (

pymodbus/exceptions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ def isError(self):
2626
class ModbusIOException(ModbusException):
2727
''' Error resulting from data i/o '''
2828

29-
def __init__(self, string=""):
29+
def __init__(self, string="", function_code=None):
3030
''' Initialize the exception
3131
:param string: The message to append to the error
3232
'''
33-
message = "[Input/Output] %s" % string
34-
ModbusException.__init__(self, message)
33+
self.fcode = function_code
34+
self.message = "[Input/Output] %s" % string
35+
ModbusException.__init__(self, self.message)
3536

3637

3738
class ParameterException(ModbusException):

pymodbus/framer/rtu_framer.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,6 @@ def sendPacket(self, message):
243243
:param message: Message to be sent over the bus
244244
:return:
245245
"""
246-
# _logger.debug("Current transaction state - {}".format(
247-
# ModbusTransactionState.to_string(self.client.state))
248-
# )
249246
while self.client.state != ModbusTransactionState.IDLE:
250247
if self.client.state == ModbusTransactionState.TRANSACTION_COMPLETE:
251248
ts = round(time.time(), 6)
@@ -269,6 +266,7 @@ def sendPacket(self, message):
269266
else:
270267
_logger.debug("Sleeping")
271268
time.sleep(self.client.silent_interval)
269+
self.client.state = ModbusTransactionState.IDLE
272270
size = self.client.send(message)
273271
# if size:
274272
# _logger.debug("Changing transaction state from 'SENDING' "

pymodbus/pdu.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ def doException(self, exception):
103103
:param exception: The exception to return
104104
:raises: An exception response
105105
"""
106-
_logger.error("Exception Response F(%d) E(%d)" %
107-
(self.function_code, exception))
108-
return ExceptionResponse(self.function_code, exception)
106+
exc = ExceptionResponse(self.function_code, exception)
107+
_logger.error(exc)
108+
return exc
109109

110110

111111
class ModbusResponse(ModbusPDU):

0 commit comments

Comments
 (0)