1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtSerialBus module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 
37 #include "qmodbusrtuserialslave.h"
38 #include "qmodbusrtuserialslave_p.h"
39 
40 #include <QtCore/qloggingcategory.h>
41 
42 QT_BEGIN_NAMESPACE
43 
44 /*!
45     \class QModbusRtuSerialSlave
46     \inmodule QtSerialBus
47     \since 5.8
48 
49     \brief The QModbusRtuSerialSlave class represents a Modbus server
50     that uses a serial port for its communication with the Modbus client.
51 
52     Communication via Modbus requires the interaction between a single Modbus
53     client instance and multiple Modbus server. This class provides the Modbus
54     server implementation via a serial port.
55 
56     Since multiple Modbus server instances can interact with a Modbus client
57     at the same time (using a serial bus), servers are identified by their
58     \l serverAddress().
59 */
60 
61 /*!
62     Constructs a QModbusRtuSerialSlave with the specified \a parent. The
63     \l serverAddress preset is \c 1.
64 */
QModbusRtuSerialSlave(QObject * parent)65 QModbusRtuSerialSlave::QModbusRtuSerialSlave(QObject *parent)
66     : QModbusServer(*new QModbusRtuSerialSlavePrivate, parent)
67 {
68     Q_D(QModbusRtuSerialSlave);
69     d->setupSerialPort();
70 }
71 
72 /*!
73     Destroys the QModbusRtuSerialSlave instance.
74 */
~QModbusRtuSerialSlave()75 QModbusRtuSerialSlave::~QModbusRtuSerialSlave()
76 {
77     close();
78 }
79 
80 /*!
81     \internal
82 */
QModbusRtuSerialSlave(QModbusRtuSerialSlavePrivate & dd,QObject * parent)83 QModbusRtuSerialSlave::QModbusRtuSerialSlave(QModbusRtuSerialSlavePrivate &dd, QObject *parent)
84     : QModbusServer(dd, parent)
85 {
86     Q_D(QModbusRtuSerialSlave);
87     d->setupSerialPort();
88 }
89 
90 /*!
91     \reimp
92 */
processesBroadcast() const93 bool QModbusRtuSerialSlave::processesBroadcast() const
94 {
95     return d_func()->m_processesBroadcast;
96 }
97 
98 /*!
99     \reimp
100 
101      \note When calling this function, existing buffered data is removed from
102      the serial port.
103 */
open()104 bool QModbusRtuSerialSlave::open()
105 {
106     if (state() == QModbusDevice::ConnectedState)
107         return true;
108 
109     Q_D(QModbusRtuSerialSlave);
110     d->setupEnvironment(); // to be done before open
111     if (d->m_serialPort->open(QIODevice::ReadWrite)) {
112         setState(QModbusDevice::ConnectedState);
113         d->m_serialPort->clear(); // only possible after open
114     } else {
115         setError(d->m_serialPort->errorString(), QModbusDevice::ConnectionError);
116     }
117     return (state() == QModbusDevice::ConnectedState);
118 }
119 
120 /*!
121     \reimp
122 */
close()123 void QModbusRtuSerialSlave::close()
124 {
125     if (state() == QModbusDevice::UnconnectedState)
126         return;
127 
128     Q_D(QModbusRtuSerialSlave);
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 slave will be answered with a Modbus exception
146     response with the exception code QModbusExceptionResponse::IllegalFunction.
147 */
processRequest(const QModbusPdu & request)148 QModbusResponse QModbusRtuSerialSlave::processRequest(const QModbusPdu &request)
149 {
150     if (request.functionCode() == QModbusRequest::EncapsulatedInterfaceTransport) {
151         quint8 meiType;
152         request.decodeData(&meiType);
153         if (meiType == EncapsulatedInterfaceTransport::CanOpenGeneralReference) {
154             return QModbusExceptionResponse(request.functionCode(),
155                 QModbusExceptionResponse::IllegalFunction);
156         }
157     }
158     return QModbusServer::processRequest(request);
159 }
160 
161 QT_END_NAMESPACE
162 
163 #include "moc_qmodbusrtuserialslave.cpp"
164