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 | */ |
57 | QModbusDevice::QModbusDevice(QObject *parent) |
58 | : QObject(*new QModbusDevicePrivate, parent) |
59 | { |
60 | } |
61 | |
62 | /*! |
63 | \internal |
64 | */ |
65 | QModbusDevice::QModbusDevice(QModbusDevicePrivate &dd, QObject *parent) |
66 | : QObject(dd, parent) |
67 | { |
68 | } |
69 | |
70 | /*! |
71 | Destroys the QModbusDevice instance |
72 | */ |
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 | */ |
123 | 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(akey: 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 | */ |
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(akey: parameter, avalue: 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 | */ |
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 | */ |
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 | */ |
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(state: newState); |
291 | } |
292 | |
293 | /*! |
294 | Returns the current state of the device. |
295 | |
296 | \sa setState(), stateChanged() |
297 | */ |
298 | 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 | */ |
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 | */ |
324 | 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 | */ |
334 | 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 | */ |
348 | 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 | |