Skip to content

Commit 4efd113

Browse files
committed
Add support for pyserial exclusive access mode.
Handy for preventing two applications from trying to access the same port simultaneously.
1 parent d552c1b commit 4efd113

File tree

7 files changed

+40
-0
lines changed

7 files changed

+40
-0
lines changed

pymodbus/client/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def __init__(
7777
bytesize=kwargs.get("bytesize", None),
7878
parity=kwargs.get("parity", None),
7979
stopbits=kwargs.get("stopbits", None),
80+
exclusive=kwargs.get("exclusive", None),
8081
handle_local_echo=kwargs.get("handle_local_echo", False),
8182
),
8283
False,
@@ -345,6 +346,7 @@ def __init__( # pylint: disable=too-many-arguments
345346
bytesize=kwargs.get("bytesize", None),
346347
parity=kwargs.get("parity", None),
347348
stopbits=kwargs.get("stopbits", None),
349+
exclusive=kwargs.get("exclusive", None),
348350
handle_local_echo=kwargs.get("handle_local_echo", False),
349351
on_reconnect_callback = on_reconnect_callback,
350352
),

pymodbus/client/serial.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AsyncModbusSerialClient(ModbusBaseClient, asyncio.Protocol):
3535
:param bytesize: Number of bits per byte 7-8.
3636
:param parity: 'E'ven, 'O'dd or 'N'one
3737
:param stopbits: Number of stop bits 1, 1.5, 2.
38+
:param exclusive: Set exclusive access mode (POSIX only).
3839
:param handle_local_echo: Discard local echo from dongle.
3940
4041
Common optional parameters:
@@ -72,6 +73,7 @@ def __init__(
7273
bytesize: int = 8,
7374
parity: str = "N",
7475
stopbits: int = 1,
76+
exclusive: bool | None = None,
7577
**kwargs: Any,
7678
) -> None:
7779
"""Initialize Asyncio Modbus Serial Client."""
@@ -90,6 +92,7 @@ def __init__(
9092
bytesize=bytesize,
9193
parity=parity,
9294
stopbits=stopbits,
95+
exclusive=exclusive,
9396
**kwargs,
9497
)
9598

@@ -117,6 +120,7 @@ class ModbusSerialClient(ModbusBaseSyncClient):
117120
:param bytesize: Number of bits per byte 7-8.
118121
:param parity: 'E'ven, 'O'dd or 'N'one
119122
:param stopbits: Number of stop bits 0-2.
123+
:param exclusive: Set exclusive access mode (POSIX only).
120124
:param handle_local_echo: Discard local echo from dongle.
121125
122126
Common optional parameters:
@@ -162,6 +166,7 @@ def __init__(
162166
bytesize: int = 8,
163167
parity: str = "N",
164168
stopbits: int = 1,
169+
exclusive: bool | None = None,
165170
**kwargs: Any,
166171
) -> None:
167172
"""Initialize Modbus Serial Client."""
@@ -173,6 +178,7 @@ def __init__(
173178
bytesize=bytesize,
174179
parity=parity,
175180
stopbits=stopbits,
181+
exclusive=exclusive,
176182
**kwargs,
177183
)
178184
self.socket = None
@@ -210,6 +216,7 @@ def connect(self):
210216
stopbits=self.comm_params.stopbits,
211217
baudrate=self.comm_params.baudrate,
212218
parity=self.comm_params.parity,
219+
exclusive=self.comm_params.exclusive,
213220
)
214221
if self.params.strict:
215222
self.socket.interCharTimeout = self.inter_char_timeout

pymodbus/repl/client/helper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
"set_baudrate",
6060
"get_timeout",
6161
"set_timeout",
62+
"get_exclusive",
63+
"set_exclusive",
6264
"get_serial_settings",
6365
]
6466
CLIENT_ATTRIBUTES: list[str] = []

pymodbus/repl/client/main.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@ def tcp(ctx, host, port, framer):
388388
default=2,
389389
type=float,
390390
)
391+
@click.option(
392+
"--exclusive",
393+
help="Set exclusive access mode (POSIX only).",
394+
default=None,
395+
type=bool,
396+
)
391397
def serial( # pylint: disable=too-many-arguments
392398
ctx,
393399
method,
@@ -401,6 +407,7 @@ def serial( # pylint: disable=too-many-arguments
401407
dsrdtr,
402408
timeout,
403409
write_timeout,
410+
exclusive,
404411
):
405412
"""Define serial communication."""
406413
method = method.lower()
@@ -426,6 +433,7 @@ def serial( # pylint: disable=too-many-arguments
426433
dsrdtr=dsrdtr,
427434
timeout=timeout,
428435
write_timeout=write_timeout,
436+
exclusive=exclusive,
429437
**ctx.obj,
430438
)
431439
cli = CLI(client)

pymodbus/repl/client/mclient.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,22 @@ def set_timeout(self, value):
658658
if self.is_socket_open():
659659
self.close()
660660

661+
def get_exclusive(self):
662+
"""Get exclusive access mode (POSIX only).
663+
664+
:return: Current exclusive access mode
665+
"""
666+
return self.params.exclusive
667+
668+
def set_exclusive(self, value):
669+
"""Set exclusive access mode (POSIX only).
670+
671+
:param value: Possible values (True, False)
672+
"""
673+
self.params.exclusive = bool(value)
674+
if self.is_socket_open():
675+
self.close()
676+
661677
def get_serial_settings(self):
662678
"""Get Current Serial port settings.
663679
@@ -672,6 +688,7 @@ def get_serial_settings(self):
672688
"read timeout": self.comm_params.timeout_connect,
673689
"t1.5": self.inter_char_timeout,
674690
"t3.5": self.silent_interval,
691+
"exclusive": self.comm_params.exclusive,
675692
}
676693

677694

pymodbus/server/async_io.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ def __init__(
511511
:param parity: Which kind of parity to use
512512
:param baudrate: The baud rate to use for the serial device
513513
:param timeout: The timeout to use for the serial device
514+
:param exclusive: Set exclusive access mode (POSIX only)
514515
:param handle_local_echo: (optional) Discard local echo from dongle.
515516
:param ignore_missing_slaves: True to not send errors on a request
516517
to a missing slave
@@ -533,6 +534,7 @@ def __init__(
533534
parity=kwargs.get("parity", "N"),
534535
baudrate=kwargs.get("baudrate", 19200),
535536
stopbits=kwargs.get("stopbits", 1),
537+
exclusive=kwargs.get("exclusive", None),
536538
),
537539
context=context,
538540
ignore_missing_slaves=kwargs.get("ignore_missing_slaves", False),

pymodbus/transport/transport.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class CommParams:
9595
bytesize: int | None = None
9696
parity: str | None = None
9797
stopbits: int | None = None
98+
exclusive: bool | None = None
9899

99100
@classmethod
100101
def generate_ssl(
@@ -202,6 +203,7 @@ def init_setup_connect_listen(self, host: str, port: int) -> None:
202203
parity=self.comm_params.parity,
203204
stopbits=self.comm_params.stopbits,
204205
timeout=self.comm_params.timeout_connect,
206+
exclusive=self.comm_params.exclusive,
205207
)
206208
return
207209
if self.comm_params.comm_type == CommType.UDP:

0 commit comments

Comments
 (0)