Skip to content

Commit 2cfbd82

Browse files
b2vnEmantor
authored andcommitted
driver: add modbus rtu driver
Signed-off-by: Nikolaj Rahbek <nikolaj@b2vn.org>
1 parent dc1edb0 commit 2cfbd82

13 files changed

Lines changed: 207 additions & 0 deletions

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Release 0.5.0 (unreleased)
33

44
New Features in 0.5.0
55
~~~~~~~~~~~~~~~~~~~~~
6+
- ModbusRTU driver for instruments
67
- Support for Eaton ePDU and TP-Link power strips added, either can be used as a NetworkPowerPort.
78
- Consider a combination of multiple "lg_feature" markers instead of
89
considering only the closest marker.

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ psutil==5.8.0
99
-r crossbar-requirements.txt
1010
-r onewire-requirements.txt
1111
-r modbus-requirements.txt
12+
-r modbusrtu-requirements.txt
1213
-r snmp-requirements.txt
1314
-r xena-requirements.txt
1415
-r graph-requirements.txt

doc/configuration.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,42 @@ port 53867 and use a baud rate of 115200 with the RFC2217 protocol.
6464
Used by:
6565
- `SerialDriver`_
6666

67+
ModbusRTU
68+
+++++++++
69+
Describes the resource required to use the ModbusRTU driver.
70+
`Modbus RTU <https://en.wikipedia.org/wiki/Modbus>`_ is a communication
71+
protocol used to control many different kinds of electronic systems, such as
72+
thermostats, power plants, etc.
73+
Modbus is normally implemented on top of RS-485, though this is not strictly
74+
necessary, as long as the Modbus network only has one master (and up to 256
75+
slaves).
76+
77+
The labgrid driver is implemented using the minimalmodbus Python library.
78+
The implementation only supports that labgrid will be the master on the Modbus
79+
network.
80+
For more information, see `minimalmodbus
81+
<https://minimalmodbus.readthedocs.io/en/stable/>`_.
82+
83+
This resource and driver only supports local usage and will not work with an
84+
exporter.
85+
86+
.. code-block:: yaml
87+
88+
ModbusRTU:
89+
port: "/dev/ttyUSB0"
90+
address: 16
91+
speed: 115200
92+
timeout: 0.25
93+
94+
Arguments:
95+
- port (str): tty the instrument is connected to, e.g. '/dev/ttyUSB0'
96+
- address (int): slave address on the modbus, e.g. 16
97+
- baudrate (bool): optional, default is 115200
98+
- timeout (bool): optional, timeout in seconds. Default is 0.25 s
99+
100+
Used by:
101+
- `ModbusRTUDriver`_
102+
67103
USBSerialPort
68104
+++++++++++++
69105
A USBSerialPort describes a serial port which is connected via USB and is
@@ -1226,6 +1262,19 @@ Arguments:
12261262
- timeout (float, default=3.0): time in seconds to wait for a network serial port before
12271263
an error occurs
12281264

1265+
ModbusRTUDriver
1266+
~~~~~~~~~~~~~~~
1267+
A ModbusRTUDriver connects to a ModbusRTU resource. This driver only supports
1268+
local usage and will not work with an exporter.
1269+
1270+
.. code-block:: yaml
1271+
1272+
ModbusRTUDriver: {}
1273+
1274+
Binds to:
1275+
port:
1276+
- `ModbusRTU`_
1277+
12291278
ShellDriver
12301279
~~~~~~~~~~~
12311280
A ShellDriver binds on top of a `ConsoleProtocol` and is designed to interact

doc/getting_started.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ Modbus
100100
Modbus support requires an additional package `pyModbusTCP`. It is included in
101101
the `modbus-requirements.txt` file.
102102

103+
ModbusRTU
104+
+++++++++
105+
Modbus support requires an additional package `minimalmodbus`. It is included in
106+
the `modbusrtu-requirements.txt` file.
103107

104108
Running Your First Test
105109
-----------------------

examples/modbusrtu/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import pytest
2+
3+
4+
@pytest.fixture(scope='session')
5+
def instrument(target):
6+
_modbus = target.get_driver('ModbusRTUDriver')
7+
return _modbus

examples/modbusrtu/env.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
targets:
2+
main:
3+
resources:
4+
ModbusRTU:
5+
port: "/dev/ttyUSB0"
6+
address: 16
7+
speed: 115200
8+
timeout: 0.25
9+
drivers:
10+
ModbusRTUDriver: {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
def test_modbusrtu_example(instrument):
2+
"""
3+
The interface for the modbus RTU driver is a thin adapter, having same
4+
interface as provided by the minimalmodbus package. Therefore, for more
5+
infromation on how to use the labgrid modbus RTU driver, please refer to
6+
the minimalmodbus documentation.
7+
"""
8+
9+
uptime_register_addr = 0x107
10+
instrument.write_register(uptime_register_addr, 0, functioncode=6)
11+
value = instrument.read_register(uptime_register_addr)
12+
13+
assert value <= 1

labgrid/driver/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from .common import Driver
2121
from .qemudriver import QEMUDriver
2222
from .modbusdriver import ModbusCoilDriver
23+
from .modbusrtudriver import ModbusRTUDriver
2324
from .sigrokdriver import SigrokDriver
2425
from .usbstoragedriver import USBStorageDriver, NetworkUSBStorageDriver, Mode
2526
from .resetdriver import DigitalOutputResetDriver

labgrid/driver/modbusrtudriver.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from importlib import import_module
2+
import attr
3+
4+
from ..factory import target_factory
5+
from .common import Driver
6+
7+
8+
@target_factory.reg_driver
9+
@attr.s(eq=False)
10+
class ModbusRTUDriver(Driver):
11+
bindings = {"resource": "ModbusRTU"}
12+
13+
def __attrs_post_init__(self):
14+
super().__attrs_post_init__()
15+
self._modbus = import_module('minimalmodbus')
16+
self.instrument = None
17+
18+
def on_activate(self):
19+
self.instrument = self._modbus.Instrument(
20+
self.resource.port,
21+
self.resource.address,
22+
debug=False)
23+
self.instrument.serial.baudrate = self.resource.speed
24+
self.instrument.serial.timeout = self.resource.timeout
25+
26+
self.instrument.mode = self._modbus.MODE_RTU
27+
self.instrument.clear_buffers_before_each_transaction = True
28+
29+
def on_deactivate(self):
30+
self.instrument = None
31+
32+
def read_register(self, *args, **kwargs):
33+
return self.instrument.read_register(*args, **kwargs)
34+
35+
def write_register(self, *args, **kwargs):
36+
return self.instrument.write_register(*args, **kwargs)
37+
38+
def read_registers(self, *args, **kwargs):
39+
return self.instrument.read_registers(*args, **kwargs)
40+
41+
def write_registers(self, *args, **kwargs):
42+
return self.instrument.write_registers(*args, **kwargs)
43+
44+
def read_bit(self, *args, **kwargs):
45+
return self.instrument.read_bit(*args, **kwargs)
46+
47+
def write_bit(self, *args, **kwargs):
48+
return self.instrument.write_bit(*args, **kwargs)
49+
50+
def read_string(self, *args, **kwargs):
51+
return self.instrument.read_string(*args, **kwargs)
52+
53+
def write_string(self, *args, **kwargs):
54+
return self.instrument.write_string(*args, **kwargs)

labgrid/resource/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .ethernetport import SNMPEthernetPort
33
from .serialport import RawSerialPort, NetworkSerialPort
44
from .modbus import ModbusTCPCoil
5+
from .modbusrtu import ModbusRTU
56
from .networkservice import NetworkService
67
from .onewireport import OneWirePIO
78
from .power import NetworkPowerPort

0 commit comments

Comments
 (0)