1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qmodbusrtuserialserver.h"
5#include "qmodbusrtuserialserver_p.h"
6
7#include <QtCore/qloggingcategory.h>
8
9QT_BEGIN_NAMESPACE
10
11/*!
12 \class QModbusRtuSerialServer
13 \inmodule QtSerialBus
14 \since 6.2
15
16 \brief The QModbusRtuSerialServer class represents a Modbus server
17 that uses a serial port for its communication with the Modbus client.
18
19 Communication via Modbus requires the interaction between a single Modbus
20 client instance and multiple Modbus server. This class provides the Modbus
21 server implementation via a serial port.
22
23 Since multiple Modbus server instances can interact with a Modbus client
24 at the same time (using a serial bus), servers are identified by their
25 \l serverAddress().
26*/
27
28/*!
29 Constructs a QModbusRtuSerialServer with the specified \a parent. The
30 \l serverAddress preset is \c 1.
31*/
32QModbusRtuSerialServer::QModbusRtuSerialServer(QObject *parent)
33 : QModbusServer(*new QModbusRtuSerialServerPrivate, parent)
34{
35 Q_D(QModbusRtuSerialServer);
36 d->setupSerialPort();
37}
38
39/*!
40 Destroys the QModbusRtuSerialServer instance.
41*/
42QModbusRtuSerialServer::~QModbusRtuSerialServer()
43{
44 close();
45}
46
47/*!
48 \internal
49*/
50QModbusRtuSerialServer::QModbusRtuSerialServer(QModbusRtuSerialServerPrivate &dd, QObject *parent)
51 : QModbusServer(dd, parent)
52{
53 Q_D(QModbusRtuSerialServer);
54 d->setupSerialPort();
55}
56
57/*!
58 \reimp
59*/
60bool QModbusRtuSerialServer::processesBroadcast() const
61{
62 return d_func()->m_processesBroadcast;
63}
64
65/*!
66 \since 6.2
67
68 Returns the amount of microseconds for the silent interval between two
69 consecutive Modbus messages.
70
71 \sa setInterFrameDelay()
72*/
73int QModbusRtuSerialServer::interFrameDelay() const
74{
75 Q_D(const QModbusRtuSerialServer);
76 return d->m_interFrameDelayMilliseconds * 1000;
77}
78
79/*!
80 \since 6.2
81
82 Sets the amount of \a microseconds for the silent interval between two
83 consecutive Modbus messages. By default, the class implementation will use
84 a pre-calculated value according to the Modbus specification. A active or
85 running connection is not affected by such delay changes.
86
87 \note If \a microseconds is set to -1 or \a microseconds is less than the
88 pre-calculated delay then this pre-calculated value is used as frame delay.
89*/
90void QModbusRtuSerialServer::setInterFrameDelay(int microseconds)
91{
92 Q_D(QModbusRtuSerialServer);
93 d->m_interFrameDelayMilliseconds = qCeil(v: qreal(microseconds) / 1000.);
94 d->calculateInterFrameDelay();
95}
96
97/*!
98 \reimp
99
100 \note When calling this function, existing buffered data is removed from
101 the serial port.
102*/
103bool QModbusRtuSerialServer::open()
104{
105 if (state() == QModbusDevice::ConnectedState)
106 return true;
107
108 Q_D(QModbusRtuSerialServer);
109 d->setupEnvironment(); // to be done before open
110 if (d->m_serialPort->open(mode: QIODevice::ReadWrite)) {
111 setState(QModbusDevice::ConnectedState);
112 d->m_serialPort->clear(); // only possible after open
113 } else {
114 setError(errorText: d->m_serialPort->errorString(), error: QModbusDevice::ConnectionError);
115 }
116 return (state() == QModbusDevice::ConnectedState);
117}
118
119/*!
120 \reimp
121*/
122void QModbusRtuSerialServer::close()
123{
124 if (state() == QModbusDevice::UnconnectedState)
125 return;
126
127 Q_D(QModbusRtuSerialServer);
128 if (d->m_serialPort->isOpen())
129 d->m_serialPort->close();
130
131 setState(QModbusDevice::UnconnectedState);
132}
133
134/*!
135 \reimp
136
137 Processes the Modbus client request specified by \a request and returns a
138 Modbus response.
139
140 The Modbus function \l QModbusRequest::EncapsulatedInterfaceTransport with
141 MEI Type 13 (0x0D) CANopen General Reference is filtered out because it is
142 usually Modbus TCP or Modbus serial ASCII only.
143
144 A request to the RTU serial server will be answered with a Modbus exception
145 response with the exception code QModbusExceptionResponse::IllegalFunction.
146*/
147QModbusResponse QModbusRtuSerialServer::processRequest(const QModbusPdu &request)
148{
149 if (request.functionCode() == QModbusRequest::EncapsulatedInterfaceTransport) {
150 quint8 meiType;
151 request.decodeData(newData: &meiType);
152 if (meiType == EncapsulatedInterfaceTransport::CanOpenGeneralReference) {
153 return QModbusExceptionResponse(request.functionCode(),
154 QModbusExceptionResponse::IllegalFunction);
155 }
156 }
157 return QModbusServer::processRequest(request);
158}
159
160QT_END_NAMESPACE
161

source code of qtserialbus/src/serialbus/qmodbusrtuserialserver.cpp