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

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