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 "qmodbusdevice.h"
38 #include "qmodbusdevice_p.h"
39 #include "qmodbusdataunit.h"
40 
41 #include <QtCore/qloggingcategory.h>
42 
43 QT_BEGIN_NAMESPACE
44 
45 /*!
46     \class QModbusDevice
47     \inmodule QtSerialBus
48     \since 5.8
49 
50     \brief The QModbusDevice class is the base class for Modbus classes, \l QModbusServer
51     and \l QModbusClient.
52 */
53 
54 /*!
55     Constructs a Modbus device with the specified \a parent.
56 */
QModbusDevice(QObject * parent)57 QModbusDevice::QModbusDevice(QObject *parent)
58  : QObject(*new QModbusDevicePrivate, parent)
59 {
60 }
61 
62 /*!
63     \internal
64 */
QModbusDevice(QModbusDevicePrivate & dd,QObject * parent)65 QModbusDevice::QModbusDevice(QModbusDevicePrivate &dd, QObject *parent)
66  : QObject(dd, parent)
67 {
68 }
69 
70 /*!
71     Destroys the QModbusDevice instance
72 */
~QModbusDevice()73 QModbusDevice::~QModbusDevice()
74 {
75 }
76 
77 /*!
78     \enum QModbusDevice::ConnectionParameter
79 
80     This enum describes the possible values that can be set for a Modbus device
81     connection.
82 
83     The general purpose value (and the associated types) are:
84 
85     \value SerialPortNameParameter   This parameter holds the serial port used for
86                                      device communication, e.g. COM1. \c QString
87     \value SerialParityParameter     This parameter holds the parity checking mode.
88                                      \c QSerialPort::Parity
89     \value SerialBaudRateParameter   This parameter holds the data baud rate for
90                                      the communication. \c QSerialPort::BaudRate
91     \value SerialDataBitsParameter   This parameter holds the data bits in a frame.
92                                      \c QSerialPort::DataBits
93     \value SerialStopBitsParameter   This parameter holds the number of stop bits in a
94                                      frame. \c QSerialPort::StopBits
95     \value NetworkPortParameter      This parameter holds the network port. \c int
96     \value NetworkAddressParameter   This parameter holds the host address for network
97                                      communication. \c QString
98 
99     User options:
100 
101     \value UserParameter             This enum value has been deprecated. There
102                                      will be no replacement.
103 */
104 
105 /*!
106     Returns the value associated with the given connection \a parameter. The
107     returned value can be empty.
108 
109     By default the \c QModbusDevice is initialized with some common values. The
110     serial port settings are even parity, a baud rate of 19200 bits per second,
111     eight data bits and one stop bit. The network settings for the host address
112     is set to local host and port to 502.
113 
114     \note For a serial connection to succeed, the \l SerialPortNameParameter
115     needs to be set to a valid communication port. The information about valid
116     serial ports can be obtained from \l QSerialPortInfo.
117 
118     \note If the device is already connected, the settings are taken into account
119     after reconnecting the device.
120 
121     \sa ConnectionParameter
122 */
connectionParameter(int parameter) const123 QVariant QModbusDevice::connectionParameter(int parameter) const
124 {
125     Q_D(const QModbusDevice);
126     switch (parameter) {
127 #if QT_CONFIG(modbus_serialport)
128     case SerialPortNameParameter:
129         return d->m_comPort;
130     case SerialDataBitsParameter:
131         return d->m_dataBits;
132     case SerialParityParameter:
133         return d->m_parity;
134     case SerialStopBitsParameter:
135         return d->m_stopBits;
136     case SerialBaudRateParameter:
137         return d->m_baudRate;
138 #endif
139     case NetworkPortParameter:
140         return d->m_networkPort;
141     case NetworkAddressParameter:
142         return d->m_networkAddress;
143     default:
144         break;
145     }
146     return d->m_userConnectionParams.value(parameter); // ### Qt6: remove
147 }
148 
149 /*!
150     Sets the value of \a parameter to \a value. If the \a parameter already
151     exists, the previous value is overwritten. A active or running connection
152     is not affected by such parameter changes.
153 
154     \sa ConnectionParameter
155     \sa connectionParameter()
156 */
setConnectionParameter(int parameter,const QVariant & value)157 void QModbusDevice::setConnectionParameter(int parameter, const QVariant &value)
158 {
159     Q_D(QModbusDevice);
160     switch (parameter) {
161 #if QT_CONFIG(modbus_serialport)
162     case SerialPortNameParameter:
163         d->m_comPort = value.toString();
164         break;
165     case SerialDataBitsParameter:
166         d->m_dataBits = QSerialPort::DataBits(value.toInt());
167         break;
168     case SerialParityParameter:
169         d->m_parity = QSerialPort::Parity(value.toInt());
170         break;
171     case SerialStopBitsParameter:
172         d->m_stopBits = QSerialPort::StopBits(value.toInt());
173         break;
174     case SerialBaudRateParameter:
175         d->m_baudRate = QSerialPort::BaudRate(value.toInt());
176         break;
177 #endif
178     case NetworkPortParameter:
179         d->m_networkPort = value.toInt();
180         break;
181     case NetworkAddressParameter:
182         d->m_networkAddress = value.toString();
183         break;
184     default:
185         d->m_userConnectionParams.insert(parameter, value); // ### Qt6: remove
186         break;
187     }
188 }
189 
190 /*!
191     \enum QModbusDevice::Error
192     This enum describes all the possible error conditions.
193 
194     \value NoError              No errors have occurred.
195     \value ReadError            An error occurred during a read operation.
196     \value WriteError           An error occurred during a write operation.
197     \value ConnectionError      An error occurred when attempting to open the
198                                 backend.
199     \value ConfigurationError   An error occurred when attempting to set a
200                                 configuration parameter.
201     \value TimeoutError         A timeout occurred during I/O. An I/O operation
202                                 did not finish within a given time frame.
203     \value ProtocolError        A Modbus specific protocol error occurred.
204     \value ReplyAbortedError    The reply was aborted due to a disconnection of
205                                 the device.
206     \value UnknownError         An unknown error occurred.
207 */
208 
209 /*!
210     \enum QModbusDevice::State
211     This enum describes all possible device states.
212 
213     \value UnconnectedState The device is disconnected.
214     \value ConnectingState  The device is being connected.
215     \value ConnectedState   The device is connected to the Modbus network.
216     \value ClosingState     The device is being closed.
217 */
218 
219 /*!
220     \fn QModbusDevice::errorOccurred(QModbusDevice::Error error)
221 
222     This signal is emitted when an error of the type, \a error, occurs.
223 */
224 
225 /*!
226     \fn void QModbusDevice::stateChanged(QModbusDevice::State state)
227 
228     This signal is emitted every time the state of the device changes.
229     The new state is represented by \a state.
230 
231     \sa setState(), state()
232 */
233 
234 /*!
235     Connects the device to the Modbus network. Returns \c true if the connection
236     process was successfully initiated; otherwise \c false. Final connection
237     success confirmation requires the \l state() changing to \l QModbusDevice::ConnectedState.
238 
239 
240     This function calls \l open() as part of its implementation.
241 
242     \sa open()
243 */
connectDevice()244 bool QModbusDevice::connectDevice()
245 {
246     Q_D(QModbusDevice);
247 
248     if (d->state != QModbusDevice::UnconnectedState)
249         return false;
250 
251     setState(ConnectingState);
252 
253     if (!open()) {
254         setState(UnconnectedState);
255         return false;
256     }
257 
258     //Connected is set by backend -> might be delayed by event loop
259     return true;
260 }
261 
262 /*!
263     Disconnects the device.
264 
265     This function calls \l close() as part of its implementation.
266 */
disconnectDevice()267 void QModbusDevice::disconnectDevice()
268 {
269     if (state() == QModbusDevice::UnconnectedState)
270         return;
271 
272     setState(QModbusDevice::ClosingState);
273 
274     //Unconnected is set by backend -> might be delayed by event loop
275     close();
276 }
277 
278 /*!
279     Sets the state of the device to \a newState. Modbus device implementations
280     must use this function to update the device state.
281 */
setState(QModbusDevice::State newState)282 void QModbusDevice::setState(QModbusDevice::State newState)
283 {
284     Q_D(QModbusDevice);
285 
286     if (newState == d->state)
287         return;
288 
289     d->state = newState;
290     emit stateChanged(newState);
291 }
292 
293 /*!
294     Returns the current state of the device.
295 
296     \sa setState(), stateChanged()
297 */
state() const298 QModbusDevice::State QModbusDevice::state() const
299 {
300     return d_func()->state;
301 }
302 
303 /*!
304     Sets the error state of the device. ModBus device implementations
305     must use this function in case of an error to set the \a error type and
306     a descriptive \a errorText.
307 
308     \sa QModbusDevice::Error
309 */
setError(const QString & errorText,QModbusDevice::Error error)310 void QModbusDevice::setError(const QString &errorText, QModbusDevice::Error error)
311 {
312     Q_D(QModbusDevice);
313 
314     d->error = error;
315     d->errorString = errorText;
316     emit errorOccurred(error);
317 }
318 
319 /*!
320     Returns the error state of the device.
321 
322     \sa QModbusDevice::Error
323 */
error() const324 QModbusDevice::Error QModbusDevice::error() const
325 {
326     return d_func()->error;
327 }
328 
329 /*!
330     Returns descriptive error text for the device error.
331 
332     \sa QModbusDevice::Error
333 */
errorString() const334 QString QModbusDevice::errorString() const
335 {
336     return d_func()->errorString;
337 }
338 
339 /*!
340     \since 5.14
341 
342     Returns the underlying \l QIODevice used for ModBus communication or
343     \c nullptr if the device was not yet fully initialized.
344 
345     \note Do not store a pointer to the underlying device, because it can be
346     invalidated at any point in time.
347 */
device() const348 QIODevice *QModbusDevice::device() const
349 {
350     return d_func()->device();
351 }
352 
353 /*!
354     \fn bool QModbusDevice::open()
355 
356     This function is called by connectDevice(). Subclasses must provide
357     an implementation that returns \c true on successful Modbus connection
358     or connection initiation; otherwise returns \c false.
359 
360     The implementation must ensure that the instance's \l state()
361     is set to \l QModbusDevice::ConnectingState or \l QModbusDevice::ConnectedState upon success; otherwise
362     \l QModbusDevice::UnconnectedState. Typically, \l QModbusDevice::ConnectingState is used
363     when the connection process reports back asynchronously and \l QModbusDevice::ConnectedState
364     in case of synchronous connect behavior.
365 
366     \sa connectDevice()
367 */
368 
369 /*!
370     \fn void QModbusDevice::close()
371 
372     This function is responsible for closing the Modbus connection.
373     The implementation must ensure that the instance's
374     \l state() is set to \l QModbusDevice::UnconnectedState.
375 
376     \sa disconnectDevice()
377 */
378 
379 Q_LOGGING_CATEGORY(QT_MODBUS, "qt.modbus")
380 Q_LOGGING_CATEGORY(QT_MODBUS_LOW, "qt.modbus.lowlevel")
381 
382 QT_END_NAMESPACE
383