Skip to content

Commit d24163d

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 d24163d

File tree

12 files changed

+45
-0
lines changed

12 files changed

+45
-0
lines changed

examples/client_async.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def setup_async_client(description=None, cmdline=None):
8484
# bytesize=8,
8585
# parity="N",
8686
# stopbits=1,
87+
# exclusive=None,
8788
# handle_local_echo=False,
8889
)
8990
elif args.comm == "tls":

examples/client_sync.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def setup_sync_client(description=None, cmdline=None):
9393
# bytesize=8,
9494
# parity="N",
9595
# stopbits=1,
96+
# exclusive=None,
9697
# handle_local_echo=False,
9798
)
9899
elif args.comm == "tls":

examples/server_async.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ async def run_async_server(args):
190190
# bytesize=8, # The bytesize of the serial messages
191191
# parity="N", # Which kind of parity to use
192192
baudrate=args.baudrate, # The baud rate to use for the serial device
193+
# exclusive=None, # The exclusive access mode (POSIX only)
193194
# handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor
194195
# ignore_missing_slaves=True, # ignore request to a missing slave
195196
# broadcast_enable=False, # treat slave_id 0 as broadcast address,

examples/server_sync.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ def run_sync_server(args):
100100
# bytesize=7, # The bytesize of the serial messages
101101
# parity="E", # Which kind of parity to use
102102
baudrate=args.baudrate, # The baud rate to use for the serial device
103+
# exclusive=None, # The exclusive access mode (POSIX only)
103104
# handle_local_echo=False, # Handle local echo of the USB-to-RS485 adaptor
104105
# ignore_missing_slaves=True, # ignore request to a missing slave
105106
# broadcast_enable=False, # treat slave_id 0 as broadcast address,

examples/simple_sync_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def run_sync_simple_client(comm, host, port, framer=Framer.SOCKET):
6565
bytesize=8,
6666
parity="N",
6767
stopbits=1,
68+
# exclusive=None,
6869
# handle_local_echo=False,
6970
)
7071
elif comm == "tls":

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

0 commit comments

Comments
 (0)