1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Denis Shienkov <denis.shienkov@gmail.com> |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtSerialPort module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | #include <QtSerialPort/QSerialPort> |
31 | #include <QtSerialPort/QSerialPortInfo> |
32 | |
33 | #include <QThread> |
34 | |
35 | Q_DECLARE_METATYPE(QSerialPort::SerialPortError); |
36 | Q_DECLARE_METATYPE(QSerialPort::BaudRate); |
37 | Q_DECLARE_METATYPE(QSerialPort::DataBits); |
38 | Q_DECLARE_METATYPE(QSerialPort::Parity); |
39 | Q_DECLARE_METATYPE(QSerialPort::StopBits); |
40 | Q_DECLARE_METATYPE(QSerialPort::FlowControl); |
41 | Q_DECLARE_METATYPE(QIODevice::OpenMode); |
42 | Q_DECLARE_METATYPE(QIODevice::OpenModeFlag); |
43 | Q_DECLARE_METATYPE(Qt::ConnectionType); |
44 | |
45 | class tst_QSerialPort : public QObject |
46 | { |
47 | Q_OBJECT |
48 | public: |
49 | explicit tst_QSerialPort(); |
50 | |
51 | static void enterLoop(int secs) |
52 | { |
53 | ++loopLevel; |
54 | QTestEventLoop::instance().enterLoop(secs); |
55 | --loopLevel; |
56 | } |
57 | |
58 | static void enterLoopMsecs(int msecs) |
59 | { |
60 | ++loopLevel; |
61 | QTestEventLoop::instance().enterLoopMSecs(ms: msecs); |
62 | --loopLevel; |
63 | } |
64 | |
65 | static void exitLoop() |
66 | { |
67 | if (loopLevel > 0) |
68 | QTestEventLoop::instance().exitLoop(); |
69 | } |
70 | |
71 | static bool timeout() |
72 | { |
73 | return QTestEventLoop::instance().timeout(); |
74 | } |
75 | |
76 | private slots: |
77 | void initTestCase(); |
78 | |
79 | void defaultConstruct(); |
80 | void constructByName(); |
81 | void constructByInfo(); |
82 | |
83 | void openExisting_data(); |
84 | void openExisting(); |
85 | void openNotExisting_data(); |
86 | void openNotExisting(); |
87 | |
88 | void baudRate_data(); |
89 | void baudRate(); |
90 | void dataBits_data(); |
91 | void dataBits(); |
92 | void parity_data(); |
93 | void parity(); |
94 | void stopBits_data(); |
95 | void stopBits(); |
96 | void flowControl_data(); |
97 | void flowControl(); |
98 | |
99 | void rts(); |
100 | void dtr(); |
101 | void independenceRtsAndDtr(); |
102 | |
103 | void flush(); |
104 | void doubleFlush(); |
105 | |
106 | void waitForBytesWritten(); |
107 | |
108 | void waitForReadyReadWithTimeout(); |
109 | void waitForReadyReadWithOneByte(); |
110 | void waitForReadyReadWithAlphabet(); |
111 | |
112 | void twoStageSynchronousLoopback(); |
113 | |
114 | void synchronousReadWrite(); |
115 | |
116 | void asynchronousWriteByBytesWritten_data(); |
117 | void asynchronousWriteByBytesWritten(); |
118 | |
119 | void asynchronousWriteByTimer_data(); |
120 | void asynchronousWriteByTimer(); |
121 | |
122 | void asyncReadWithLimitedReadBufferSize(); |
123 | |
124 | void readBufferOverflow(); |
125 | void readAfterInputClear(); |
126 | void synchronousReadWriteAfterAsynchronousReadWrite(); |
127 | |
128 | void controlBreak(); |
129 | |
130 | void clearAfterOpen(); |
131 | |
132 | void readWriteWithDifferentBaudRate_data(); |
133 | void readWriteWithDifferentBaudRate(); |
134 | |
135 | protected slots: |
136 | void handleBytesWrittenAndExitLoopSlot(qint64 bytesWritten); |
137 | void handleBytesWrittenAndExitLoopSlot2(qint64 bytesWritten); |
138 | |
139 | private: |
140 | QString m_senderPortName; |
141 | QString m_receiverPortName; |
142 | QStringList m_availablePortNames; |
143 | |
144 | static int loopLevel; |
145 | static const QByteArray alphabetArray; |
146 | static const QByteArray newlineArray; |
147 | }; |
148 | |
149 | int tst_QSerialPort::loopLevel = 0; |
150 | |
151 | const QByteArray tst_QSerialPort::alphabetArray("ABCDEFGHIJKLMNOPQRSTUVWXUZ" ); |
152 | const QByteArray tst_QSerialPort::newlineArray("\n\r" ); |
153 | |
154 | tst_QSerialPort::tst_QSerialPort() |
155 | { |
156 | qRegisterMetaType<QSerialPort::SerialPortError>(typeName: "QSerialPort::SerialPortError" ); |
157 | } |
158 | |
159 | void tst_QSerialPort::initTestCase() |
160 | { |
161 | m_senderPortName = QString::fromLocal8Bit(str: qgetenv(varName: "QTEST_SERIALPORT_SENDER" )); |
162 | m_receiverPortName = QString::fromLocal8Bit(str: qgetenv(varName: "QTEST_SERIALPORT_RECEIVER" )); |
163 | if (m_senderPortName.isEmpty() || m_receiverPortName.isEmpty()) { |
164 | static const char message[] = |
165 | "Test doesn't work because the names of serial ports aren't found in env.\n" |
166 | "Please set environment variables:\n" |
167 | " QTEST_SERIALPORT_SENDER to name of output serial port\n" |
168 | " QTEST_SERIALPORT_RECEIVER to name of input serial port\n" |
169 | "Specify short names of port" |
170 | #if defined(Q_OS_UNIX) |
171 | ", like: ttyS0\n" ; |
172 | #elif defined(Q_OS_WIN32) |
173 | ", like: COM1\n" ; |
174 | #else |
175 | "\n" ; |
176 | #endif |
177 | |
178 | QSKIP(message); |
179 | } else { |
180 | m_availablePortNames << m_senderPortName << m_receiverPortName; |
181 | } |
182 | } |
183 | |
184 | void tst_QSerialPort::defaultConstruct() |
185 | { |
186 | QSerialPort serialPort; |
187 | |
188 | QCOMPARE(serialPort.error(), QSerialPort::NoError); |
189 | QVERIFY(!serialPort.errorString().isEmpty()); |
190 | |
191 | // properties |
192 | const qint32 defaultBaudRate = static_cast<qint32>(QSerialPort::Baud9600); |
193 | QCOMPARE(serialPort.baudRate(), defaultBaudRate); |
194 | QCOMPARE(serialPort.baudRate(QSerialPort::Input), defaultBaudRate); |
195 | QCOMPARE(serialPort.baudRate(QSerialPort::Output), defaultBaudRate); |
196 | QCOMPARE(serialPort.dataBits(), QSerialPort::Data8); |
197 | QCOMPARE(serialPort.parity(), QSerialPort::NoParity); |
198 | QCOMPARE(serialPort.stopBits(), QSerialPort::OneStop); |
199 | QCOMPARE(serialPort.flowControl(), QSerialPort::NoFlowControl); |
200 | |
201 | QCOMPARE(serialPort.pinoutSignals(), QSerialPort::NoSignal); |
202 | QCOMPARE(serialPort.isRequestToSend(), false); |
203 | QCOMPARE(serialPort.isDataTerminalReady(), false); |
204 | |
205 | // QIODevice |
206 | QCOMPARE(serialPort.openMode(), QIODevice::NotOpen); |
207 | QVERIFY(!serialPort.isOpen()); |
208 | QVERIFY(!serialPort.isReadable()); |
209 | QVERIFY(!serialPort.isWritable()); |
210 | QVERIFY(serialPort.isSequential()); |
211 | QCOMPARE(serialPort.canReadLine(), false); |
212 | QCOMPARE(serialPort.pos(), qlonglong(0)); |
213 | QCOMPARE(serialPort.size(), qlonglong(0)); |
214 | QVERIFY(serialPort.atEnd()); |
215 | QCOMPARE(serialPort.bytesAvailable(), qlonglong(0)); |
216 | QCOMPARE(serialPort.bytesToWrite(), qlonglong(0)); |
217 | |
218 | char c; |
219 | QCOMPARE(serialPort.read(&c, 1), qlonglong(-1)); |
220 | QCOMPARE(serialPort.write(&c, 1), qlonglong(-1)); |
221 | } |
222 | |
223 | void tst_QSerialPort::constructByName() |
224 | { |
225 | QSerialPort serialPort(m_senderPortName); |
226 | QCOMPARE(serialPort.portName(), m_senderPortName); |
227 | serialPort.setPortName(m_receiverPortName); |
228 | QCOMPARE(serialPort.portName(), m_receiverPortName); |
229 | } |
230 | |
231 | void tst_QSerialPort::constructByInfo() |
232 | { |
233 | QSerialPortInfo senderPortInfo(m_senderPortName); |
234 | QSerialPortInfo receiverPortInfo(m_receiverPortName); |
235 | |
236 | #if defined(Q_OS_UNIX) |
237 | if (senderPortInfo.isNull() || receiverPortInfo.isNull()) { |
238 | static const char message[] = |
239 | "Test doesn't work because the specified serial ports aren't" |
240 | " found in system and can't be constructed by QSerialPortInfo.\n" ; |
241 | QSKIP(message); |
242 | } |
243 | #endif |
244 | |
245 | QSerialPort serialPort(senderPortInfo); |
246 | QCOMPARE(serialPort.portName(), m_senderPortName); |
247 | serialPort.setPort(receiverPortInfo); |
248 | QCOMPARE(serialPort.portName(), m_receiverPortName); |
249 | } |
250 | |
251 | void tst_QSerialPort::openExisting_data() |
252 | { |
253 | QTest::addColumn<int>(name: "openMode" ); |
254 | QTest::addColumn<bool>(name: "openResult" ); |
255 | QTest::addColumn<QSerialPort::SerialPortError>(name: "errorCode" ); |
256 | |
257 | QTest::newRow(dataTag: "NotOpen" ) << int(QIODevice::NotOpen) << false << QSerialPort::UnsupportedOperationError; |
258 | QTest::newRow(dataTag: "ReadOnly" ) << int(QIODevice::ReadOnly) << true << QSerialPort::NoError; |
259 | QTest::newRow(dataTag: "WriteOnly" ) << int(QIODevice::WriteOnly) << true << QSerialPort::NoError; |
260 | QTest::newRow(dataTag: "ReadWrite" ) << int(QIODevice::ReadWrite) << true << QSerialPort::NoError; |
261 | QTest::newRow(dataTag: "Append" ) << int(QIODevice::Append) << false << QSerialPort::UnsupportedOperationError; |
262 | QTest::newRow(dataTag: "Truncate" ) << int(QIODevice::Truncate) << false << QSerialPort::UnsupportedOperationError; |
263 | QTest::newRow(dataTag: "Text" ) << int(QIODevice::Text) << false << QSerialPort::UnsupportedOperationError; |
264 | QTest::newRow(dataTag: "Unbuffered" ) << int(QIODevice::Unbuffered) << false << QSerialPort::UnsupportedOperationError; |
265 | } |
266 | |
267 | void tst_QSerialPort::openExisting() |
268 | { |
269 | QFETCH(int, openMode); |
270 | QFETCH(bool, openResult); |
271 | QFETCH(QSerialPort::SerialPortError, errorCode); |
272 | |
273 | for (const QString &serialPortName : qAsConst(t&: m_availablePortNames)) { |
274 | QSerialPort serialPort(serialPortName); |
275 | QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred); |
276 | QVERIFY(errorSpy.isValid()); |
277 | |
278 | QCOMPARE(serialPort.portName(), serialPortName); |
279 | QCOMPARE(serialPort.open(QIODevice::OpenMode(openMode)), openResult); |
280 | QCOMPARE(serialPort.isOpen(), openResult); |
281 | QCOMPARE(serialPort.error(), errorCode); |
282 | |
283 | QCOMPARE(errorSpy.count(), 1); |
284 | QCOMPARE(qvariant_cast<QSerialPort::SerialPortError>(errorSpy.at(0).at(0)), errorCode); |
285 | } |
286 | } |
287 | |
288 | void tst_QSerialPort::openNotExisting_data() |
289 | { |
290 | QTest::addColumn<QString>(name: "serialPortName" ); |
291 | QTest::addColumn<bool>(name: "openResult" ); |
292 | QTest::addColumn<QSerialPort::SerialPortError>(name: "errorCode" ); |
293 | |
294 | QTest::newRow(dataTag: "Empty" ) << QString("" ) << false << QSerialPort::DeviceNotFoundError; |
295 | QTest::newRow(dataTag: "Null" ) << QString() << false << QSerialPort::DeviceNotFoundError; |
296 | QTest::newRow(dataTag: "NotExists" ) << QString("ABCDEF" ) << false << QSerialPort::DeviceNotFoundError; |
297 | } |
298 | |
299 | void tst_QSerialPort::openNotExisting() |
300 | { |
301 | QFETCH(QString, serialPortName); |
302 | QFETCH(bool, openResult); |
303 | //QFETCH(QSerialPort::SerialPortError, errorCode); |
304 | |
305 | QSerialPort serialPort(serialPortName); |
306 | |
307 | QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred); |
308 | QVERIFY(errorSpy.isValid()); |
309 | |
310 | QCOMPARE(serialPort.portName(), serialPortName); |
311 | QCOMPARE(serialPort.open(QIODevice::ReadOnly), openResult); |
312 | QCOMPARE(serialPort.isOpen(), openResult); |
313 | //QCOMPARE(serialPort.error(), errorCode); |
314 | |
315 | //QCOMPARE(errorSpy.count(), 1); |
316 | //QCOMPARE(qvariant_cast<QSerialPort::SerialPortError>(errorSpy.at(0).at(0)), errorCode); |
317 | } |
318 | |
319 | void tst_QSerialPort::baudRate_data() |
320 | { |
321 | QTest::addColumn<qint32>(name: "baudrate" ); |
322 | QTest::newRow(dataTag: "Baud1200" ) << static_cast<qint32>(QSerialPort::Baud1200); |
323 | QTest::newRow(dataTag: "Baud2400" ) << static_cast<qint32>(QSerialPort::Baud2400); |
324 | QTest::newRow(dataTag: "Baud4800" ) << static_cast<qint32>(QSerialPort::Baud4800); |
325 | QTest::newRow(dataTag: "Baud9600" ) << static_cast<qint32>(QSerialPort::Baud9600); |
326 | QTest::newRow(dataTag: "Baud19200" ) << static_cast<qint32>(QSerialPort::Baud19200); |
327 | QTest::newRow(dataTag: "Baud38400" ) << static_cast<qint32>(QSerialPort::Baud38400); |
328 | QTest::newRow(dataTag: "Baud57600" ) << static_cast<qint32>(QSerialPort::Baud57600); |
329 | QTest::newRow(dataTag: "Baud115200" ) << static_cast<qint32>(QSerialPort::Baud115200); |
330 | |
331 | QTest::newRow(dataTag: "31250" ) << 31250; // custom baudrate (MIDI) |
332 | } |
333 | |
334 | void tst_QSerialPort::baudRate() |
335 | { |
336 | QFETCH(qint32, baudrate); |
337 | |
338 | { |
339 | // setup before opening |
340 | QSerialPort serialPort(m_senderPortName); |
341 | QVERIFY(serialPort.setBaudRate(baudrate)); |
342 | QCOMPARE(serialPort.baudRate(), baudrate); |
343 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
344 | } |
345 | |
346 | { |
347 | // setup after opening |
348 | QSerialPort serialPort(m_senderPortName); |
349 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
350 | QVERIFY(serialPort.setBaudRate(baudrate)); |
351 | QCOMPARE(serialPort.baudRate(), baudrate); |
352 | } |
353 | } |
354 | |
355 | void tst_QSerialPort::dataBits_data() |
356 | { |
357 | QTest::addColumn<QSerialPort::DataBits>(name: "databits" ); |
358 | QTest::newRow(dataTag: "Data5" ) << QSerialPort::Data5; |
359 | QTest::newRow(dataTag: "Data6" ) << QSerialPort::Data6; |
360 | QTest::newRow(dataTag: "Data7" ) << QSerialPort::Data7; |
361 | QTest::newRow(dataTag: "Data8" ) << QSerialPort::Data8; |
362 | } |
363 | |
364 | void tst_QSerialPort::dataBits() |
365 | { |
366 | QFETCH(QSerialPort::DataBits, databits); |
367 | |
368 | { |
369 | // setup before opening |
370 | QSerialPort serialPort(m_senderPortName); |
371 | QVERIFY(serialPort.setDataBits(databits)); |
372 | QCOMPARE(serialPort.dataBits(), databits); |
373 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
374 | } |
375 | |
376 | { |
377 | // setup after opening |
378 | QSerialPort serialPort(m_senderPortName); |
379 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
380 | QVERIFY(serialPort.setDataBits(databits)); |
381 | QCOMPARE(serialPort.dataBits(), databits); |
382 | } |
383 | } |
384 | |
385 | void tst_QSerialPort::parity_data() |
386 | { |
387 | QTest::addColumn<QSerialPort::Parity>(name: "parity" ); |
388 | QTest::newRow(dataTag: "NoParity" ) << QSerialPort::NoParity; |
389 | QTest::newRow(dataTag: "EvenParity" ) << QSerialPort::EvenParity; |
390 | QTest::newRow(dataTag: "OddParity" ) << QSerialPort::OddParity; |
391 | QTest::newRow(dataTag: "SpaceParity" ) << QSerialPort::SpaceParity; |
392 | QTest::newRow(dataTag: "MarkParity" ) << QSerialPort::MarkParity; |
393 | } |
394 | |
395 | void tst_QSerialPort::parity() |
396 | { |
397 | QFETCH(QSerialPort::Parity, parity); |
398 | |
399 | { |
400 | // setup before opening |
401 | QSerialPort serialPort(m_senderPortName); |
402 | QVERIFY(serialPort.setParity(parity)); |
403 | QCOMPARE(serialPort.parity(), parity); |
404 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
405 | } |
406 | |
407 | { |
408 | // setup after opening |
409 | QSerialPort serialPort(m_senderPortName); |
410 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
411 | QVERIFY(serialPort.setParity(parity)); |
412 | QCOMPARE(serialPort.parity(), parity); |
413 | } |
414 | } |
415 | |
416 | void tst_QSerialPort::stopBits_data() |
417 | { |
418 | QTest::addColumn<QSerialPort::StopBits>(name: "stopbits" ); |
419 | QTest::newRow(dataTag: "OneStop" ) << QSerialPort::OneStop; |
420 | #ifdef Q_OS_WIN |
421 | QTest::newRow("OneAndHalfStop" ) << QSerialPort::OneAndHalfStop; |
422 | #endif |
423 | QTest::newRow(dataTag: "TwoStop" ) << QSerialPort::TwoStop; |
424 | } |
425 | |
426 | void tst_QSerialPort::stopBits() |
427 | { |
428 | QFETCH(QSerialPort::StopBits, stopbits); |
429 | |
430 | { |
431 | // setup before opening |
432 | QSerialPort serialPort(m_senderPortName); |
433 | QVERIFY(serialPort.setStopBits(stopbits)); |
434 | QCOMPARE(serialPort.stopBits(), stopbits); |
435 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
436 | } |
437 | |
438 | { |
439 | // setup after opening |
440 | QSerialPort serialPort(m_senderPortName); |
441 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
442 | QVERIFY(serialPort.setStopBits(stopbits)); |
443 | QCOMPARE(serialPort.stopBits(), stopbits); |
444 | } |
445 | } |
446 | |
447 | void tst_QSerialPort::flowControl_data() |
448 | { |
449 | QTest::addColumn<QSerialPort::FlowControl>(name: "flowcontrol" ); |
450 | QTest::newRow(dataTag: "NoFlowControl" ) << QSerialPort::NoFlowControl; |
451 | QTest::newRow(dataTag: "HardwareControl" ) << QSerialPort::HardwareControl; |
452 | QTest::newRow(dataTag: "SoftwareControl" ) << QSerialPort::SoftwareControl; |
453 | } |
454 | |
455 | void tst_QSerialPort::flowControl() |
456 | { |
457 | QFETCH(QSerialPort::FlowControl, flowcontrol); |
458 | |
459 | { |
460 | // setup before opening |
461 | QSerialPort serialPort(m_senderPortName); |
462 | QVERIFY(serialPort.setFlowControl(flowcontrol)); |
463 | QCOMPARE(serialPort.flowControl(), flowcontrol); |
464 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
465 | } |
466 | |
467 | { |
468 | // setup after opening |
469 | QSerialPort serialPort(m_senderPortName); |
470 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
471 | QVERIFY(serialPort.setFlowControl(flowcontrol)); |
472 | QCOMPARE(serialPort.flowControl(), flowcontrol); |
473 | } |
474 | } |
475 | |
476 | void tst_QSerialPort::rts() |
477 | { |
478 | QSerialPort serialPort(m_senderPortName); |
479 | |
480 | QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred); |
481 | QVERIFY(errorSpy.isValid()); |
482 | QSignalSpy rtsSpy(&serialPort, &QSerialPort::requestToSendChanged); |
483 | QVERIFY(rtsSpy.isValid()); |
484 | |
485 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
486 | |
487 | // no flow control |
488 | QVERIFY(serialPort.setFlowControl(QSerialPort::NoFlowControl)); |
489 | const bool toggle1 = !serialPort.isRequestToSend(); |
490 | QVERIFY(serialPort.setRequestToSend(toggle1)); |
491 | QCOMPARE(serialPort.isRequestToSend(), toggle1); |
492 | |
493 | // software flow control |
494 | QVERIFY(serialPort.setFlowControl(QSerialPort::SoftwareControl)); |
495 | const bool toggle2 = !serialPort.isRequestToSend(); |
496 | QVERIFY(serialPort.setRequestToSend(toggle2)); |
497 | QCOMPARE(serialPort.isRequestToSend(), toggle2); |
498 | |
499 | // hardware flow control |
500 | QVERIFY(serialPort.setFlowControl(QSerialPort::HardwareControl)); |
501 | const bool toggle3 = !serialPort.isRequestToSend(); |
502 | QVERIFY(!serialPort.setRequestToSend(toggle3)); // not allowed |
503 | QCOMPARE(serialPort.isRequestToSend(), !toggle3); // same as before |
504 | QCOMPARE(serialPort.error(), QSerialPort::UnsupportedOperationError); |
505 | |
506 | QCOMPARE(errorSpy.count(), 2); |
507 | QCOMPARE(qvariant_cast<QSerialPort::SerialPortError>(errorSpy.at(0).at(0)), QSerialPort::NoError); |
508 | QCOMPARE(qvariant_cast<QSerialPort::SerialPortError>(errorSpy.at(1).at(0)), QSerialPort::UnsupportedOperationError); |
509 | |
510 | QCOMPARE(rtsSpy.count(), 2); |
511 | QCOMPARE(qvariant_cast<bool>(rtsSpy.at(0).at(0)), toggle1); |
512 | QCOMPARE(qvariant_cast<bool>(rtsSpy.at(1).at(0)), toggle2); |
513 | } |
514 | |
515 | void tst_QSerialPort::dtr() |
516 | { |
517 | QSerialPort serialPort(m_senderPortName); |
518 | |
519 | QSignalSpy errorSpy(&serialPort, &QSerialPort::errorOccurred); |
520 | QVERIFY(errorSpy.isValid()); |
521 | QSignalSpy dtrSpy(&serialPort, &QSerialPort::dataTerminalReadyChanged); |
522 | QVERIFY(dtrSpy.isValid()); |
523 | |
524 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); |
525 | |
526 | // no flow control |
527 | QVERIFY(serialPort.setFlowControl(QSerialPort::NoFlowControl)); |
528 | const bool toggle1 = !serialPort.isDataTerminalReady(); |
529 | QVERIFY(serialPort.setDataTerminalReady(toggle1)); |
530 | QCOMPARE(serialPort.isDataTerminalReady(), toggle1); |
531 | |
532 | // software flow control |
533 | QVERIFY(serialPort.setFlowControl(QSerialPort::SoftwareControl)); |
534 | const bool toggle2 = !serialPort.isDataTerminalReady(); |
535 | QVERIFY(serialPort.setDataTerminalReady(toggle2)); |
536 | QCOMPARE(serialPort.isDataTerminalReady(), toggle2); |
537 | |
538 | // hardware flow control |
539 | QVERIFY(serialPort.setFlowControl(QSerialPort::HardwareControl)); |
540 | const bool toggle3 = !serialPort.isDataTerminalReady(); |
541 | QVERIFY(serialPort.setDataTerminalReady(toggle3)); |
542 | QCOMPARE(serialPort.isDataTerminalReady(), toggle3); |
543 | |
544 | QCOMPARE(errorSpy.count(), 1); |
545 | QCOMPARE(qvariant_cast<QSerialPort::SerialPortError>(errorSpy.at(0).at(0)), QSerialPort::NoError); |
546 | |
547 | QCOMPARE(dtrSpy.count(), 3); |
548 | QCOMPARE(qvariant_cast<bool>(dtrSpy.at(0).at(0)), toggle1); |
549 | QCOMPARE(qvariant_cast<bool>(dtrSpy.at(1).at(0)), toggle2); |
550 | QCOMPARE(qvariant_cast<bool>(dtrSpy.at(2).at(0)), toggle3); |
551 | } |
552 | |
553 | void tst_QSerialPort::independenceRtsAndDtr() |
554 | { |
555 | QSerialPort serialPort(m_senderPortName); |
556 | QVERIFY(serialPort.open(QIODevice::ReadWrite)); // No flow control by default! |
557 | |
558 | QVERIFY(serialPort.setDataTerminalReady(true)); |
559 | QVERIFY(serialPort.setRequestToSend(true)); |
560 | QVERIFY(serialPort.isDataTerminalReady()); |
561 | QVERIFY(serialPort.isRequestToSend()); |
562 | |
563 | // check that DTR changing does not change RTS |
564 | QVERIFY(serialPort.setDataTerminalReady(false)); |
565 | QVERIFY(!serialPort.isDataTerminalReady()); |
566 | QVERIFY(serialPort.isRequestToSend()); |
567 | QVERIFY(serialPort.setDataTerminalReady(true)); |
568 | QVERIFY(serialPort.isDataTerminalReady()); |
569 | QVERIFY(serialPort.isRequestToSend()); |
570 | |
571 | // check that RTS changing does not change DTR |
572 | QVERIFY(serialPort.setRequestToSend(false)); |
573 | QVERIFY(!serialPort.isRequestToSend()); |
574 | QVERIFY(serialPort.isDataTerminalReady()); |
575 | QVERIFY(serialPort.setRequestToSend(true)); |
576 | QVERIFY(serialPort.isRequestToSend()); |
577 | QVERIFY(serialPort.isDataTerminalReady()); |
578 | |
579 | // check that baud rate changing does not change DTR or RTS |
580 | QVERIFY(serialPort.setBaudRate(115200)); |
581 | QVERIFY(serialPort.isRequestToSend()); |
582 | QVERIFY(serialPort.isDataTerminalReady()); |
583 | |
584 | // check that data bits changing does not change DTR or RTS |
585 | QVERIFY(serialPort.setDataBits(QSerialPort::Data7)); |
586 | QVERIFY(serialPort.isRequestToSend()); |
587 | QVERIFY(serialPort.isDataTerminalReady()); |
588 | |
589 | // check that parity changing does not change DTR or RTS |
590 | QVERIFY(serialPort.setParity(QSerialPort::EvenParity)); |
591 | QVERIFY(serialPort.isRequestToSend()); |
592 | QVERIFY(serialPort.isDataTerminalReady()); |
593 | |
594 | // check that stop bits changing does not change DTR or RTS |
595 | QVERIFY(serialPort.setStopBits(QSerialPort::TwoStop)); |
596 | QVERIFY(serialPort.isRequestToSend()); |
597 | QVERIFY(serialPort.isDataTerminalReady()); |
598 | |
599 | // check that software flow control changing does not change DTR or RTS |
600 | QVERIFY(serialPort.setFlowControl(QSerialPort::SoftwareControl)); |
601 | QVERIFY(serialPort.isRequestToSend()); |
602 | QVERIFY(serialPort.isDataTerminalReady()); |
603 | } |
604 | |
605 | void tst_QSerialPort::handleBytesWrittenAndExitLoopSlot(qint64 bytesWritten) |
606 | { |
607 | QCOMPARE(bytesWritten, qint64(alphabetArray.size() + newlineArray.size())); |
608 | exitLoop(); |
609 | } |
610 | |
611 | void tst_QSerialPort::flush() |
612 | { |
613 | #ifdef Q_OS_WIN |
614 | QSKIP("flush() does not work on Windows" ); |
615 | #endif |
616 | |
617 | // the dummy device on other side also has to be open |
618 | QSerialPort dummySerialPort(m_receiverPortName); |
619 | QVERIFY(dummySerialPort.open(QIODevice::ReadOnly)); |
620 | |
621 | QSerialPort serialPort(m_senderPortName); |
622 | connect(sender: &serialPort, signal: &QSerialPort::bytesWritten, receiver: this, slot: &tst_QSerialPort::handleBytesWrittenAndExitLoopSlot); |
623 | QSignalSpy bytesWrittenSpy(&serialPort, &QSerialPort::bytesWritten); |
624 | |
625 | QVERIFY(serialPort.open(QIODevice::WriteOnly)); |
626 | serialPort.write(data: alphabetArray + newlineArray); |
627 | QCOMPARE(serialPort.bytesToWrite(), qint64(alphabetArray.size() + newlineArray.size())); |
628 | serialPort.flush(); |
629 | QCOMPARE(serialPort.bytesToWrite(), qint64(0)); |
630 | enterLoop(secs: 1); |
631 | QVERIFY2(!timeout(), "Timed out when waiting for the bytesWritten(qint64) signal." ); |
632 | QCOMPARE(bytesWrittenSpy.count(), 1); |
633 | } |
634 | |
635 | void tst_QSerialPort::handleBytesWrittenAndExitLoopSlot2(qint64 bytesWritten) |
636 | { |
637 | static qint64 bytes = 0; |
638 | bytes += bytesWritten; |
639 | |
640 | QVERIFY(bytesWritten == newlineArray.size() || bytesWritten == alphabetArray.size()); |
641 | |
642 | if (bytes == (alphabetArray.size() + newlineArray.size())) |
643 | exitLoop(); |
644 | } |
645 | |
646 | void tst_QSerialPort::doubleFlush() |
647 | { |
648 | #ifdef Q_OS_WIN |
649 | QSKIP("flush() does not work on Windows" ); |
650 | #endif |
651 | |
652 | // the dummy device on other side also has to be open |
653 | QSerialPort dummySerialPort(m_receiverPortName); |
654 | QVERIFY(dummySerialPort.open(QIODevice::ReadOnly)); |
655 | |
656 | QSerialPort serialPort(m_senderPortName); |
657 | connect(sender: &serialPort, signal: &QSerialPort::bytesWritten, receiver: this, slot: &tst_QSerialPort::handleBytesWrittenAndExitLoopSlot2); |
658 | QSignalSpy bytesWrittenSpy(&serialPort, &QSerialPort::bytesWritten); |
659 | |
660 | QVERIFY(serialPort.open(QIODevice::WriteOnly)); |
661 | serialPort.write(data: alphabetArray); |
662 | QCOMPARE(serialPort.bytesToWrite(), qint64(alphabetArray.size())); |
663 | serialPort.flush(); |
664 | QCOMPARE(serialPort.bytesToWrite(), qint64(0)); |
665 | serialPort.write(data: newlineArray); |
666 | QCOMPARE(serialPort.bytesToWrite(), qint64(newlineArray.size())); |
667 | serialPort.flush(); |
668 | QCOMPARE(serialPort.bytesToWrite(), qint64(0)); |
669 | |
670 | enterLoop(secs: 1); |
671 | QVERIFY2(!timeout(), "Timed out when waiting for the bytesWritten(qint64) signal." ); |
672 | QCOMPARE(bytesWrittenSpy.count(), 2); |
673 | } |
674 | |
675 | void tst_QSerialPort::waitForBytesWritten() |
676 | { |
677 | // the dummy device on other side also has to be open |
678 | QSerialPort dummySerialPort(m_receiverPortName); |
679 | QVERIFY(dummySerialPort.open(QIODevice::ReadOnly)); |
680 | |
681 | QSerialPort serialPort(m_senderPortName); |
682 | QVERIFY(serialPort.open(QIODevice::WriteOnly)); |
683 | serialPort.write(data: alphabetArray); |
684 | const qint64 toWrite = serialPort.bytesToWrite(); |
685 | QVERIFY(serialPort.waitForBytesWritten(1000)); |
686 | QVERIFY(toWrite > serialPort.bytesToWrite()); |
687 | } |
688 | |
689 | void tst_QSerialPort::waitForReadyReadWithTimeout() |
690 | { |
691 | // the dummy device on other side also has to be open |
692 | QSerialPort dummySerialPort(m_senderPortName); |
693 | QVERIFY(dummySerialPort.open(QIODevice::WriteOnly)); |
694 | |
695 | QSerialPort receiverSerialPort(m_receiverPortName); |
696 | QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly)); |
697 | QVERIFY(!receiverSerialPort.waitForReadyRead(5)); |
698 | QCOMPARE(receiverSerialPort.bytesAvailable(), qint64(0)); |
699 | QCOMPARE(receiverSerialPort.error(), QSerialPort::TimeoutError); |
700 | } |
701 | |
702 | void tst_QSerialPort::waitForReadyReadWithOneByte() |
703 | { |
704 | const qint64 oneByte = 1; |
705 | const int waitMsecs = 50; |
706 | |
707 | QSerialPort senderSerialPort(m_senderPortName); |
708 | QVERIFY(senderSerialPort.open(QIODevice::WriteOnly)); |
709 | QSerialPort receiverSerialPort(m_receiverPortName); |
710 | QSignalSpy readyReadSpy(&receiverSerialPort, &QSerialPort::readyRead); |
711 | QVERIFY(readyReadSpy.isValid()); |
712 | QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly)); |
713 | QCOMPARE(senderSerialPort.write(alphabetArray.constData(), oneByte), oneByte); |
714 | QVERIFY(senderSerialPort.waitForBytesWritten(waitMsecs)); |
715 | QVERIFY(receiverSerialPort.waitForReadyRead(waitMsecs)); |
716 | QCOMPARE(receiverSerialPort.bytesAvailable(), oneByte); |
717 | QCOMPARE(receiverSerialPort.error(), QSerialPort::NoError); |
718 | QCOMPARE(readyReadSpy.count(), 1); |
719 | } |
720 | |
721 | void tst_QSerialPort::waitForReadyReadWithAlphabet() |
722 | { |
723 | const int waitMsecs = 50; |
724 | |
725 | QSerialPort senderSerialPort(m_senderPortName); |
726 | QVERIFY(senderSerialPort.open(QIODevice::WriteOnly)); |
727 | QSerialPort receiverSerialPort(m_receiverPortName); |
728 | QSignalSpy readyReadSpy(&receiverSerialPort, &QSerialPort::readyRead); |
729 | QVERIFY(readyReadSpy.isValid()); |
730 | QVERIFY(receiverSerialPort.open(QIODevice::ReadOnly)); |
731 | QCOMPARE(senderSerialPort.write(alphabetArray), qint64(alphabetArray.size())); |
732 | QVERIFY(senderSerialPort.waitForBytesWritten(waitMsecs)); |
733 | |
734 | do { |
735 | QVERIFY(receiverSerialPort.waitForReadyRead(waitMsecs)); |
736 | } while (receiverSerialPort.bytesAvailable() < qint64(alphabetArray.size())); |
737 | |
738 | QCOMPARE(receiverSerialPort.error(), QSerialPort::NoError); |
739 | QVERIFY(readyReadSpy.count() > 0); |
740 | } |
741 | |
742 | void tst_QSerialPort::twoStageSynchronousLoopback() |
743 | { |
744 | QSerialPort senderPort(m_senderPortName); |
745 | QVERIFY(senderPort.open(QSerialPort::ReadWrite)); |
746 | |
747 | QSerialPort receiverPort(m_receiverPortName); |
748 | QVERIFY(receiverPort.open(QSerialPort::ReadWrite)); |
749 | |
750 | const int waitMsecs = 50; |
751 | |
752 | // first stage |
753 | senderPort.write(data: newlineArray); |
754 | senderPort.waitForBytesWritten(msecs: waitMsecs); |
755 | QTest::qSleep(ms: waitMsecs); |
756 | receiverPort.waitForReadyRead(msecs: waitMsecs); |
757 | QCOMPARE(receiverPort.bytesAvailable(), qint64(newlineArray.size())); |
758 | |
759 | receiverPort.write(data: receiverPort.readAll()); |
760 | receiverPort.waitForBytesWritten(msecs: waitMsecs); |
761 | QTest::qSleep(ms: waitMsecs); |
762 | senderPort.waitForReadyRead(msecs: waitMsecs); |
763 | QCOMPARE(senderPort.bytesAvailable(), qint64(newlineArray.size())); |
764 | QCOMPARE(senderPort.readAll(), newlineArray); |
765 | |
766 | // second stage |
767 | senderPort.write(data: newlineArray); |
768 | senderPort.waitForBytesWritten(msecs: waitMsecs); |
769 | QTest::qSleep(ms: waitMsecs); |
770 | receiverPort.waitForReadyRead(msecs: waitMsecs); |
771 | QCOMPARE(receiverPort.bytesAvailable(), qint64(newlineArray.size())); |
772 | receiverPort.write(data: receiverPort.readAll()); |
773 | receiverPort.waitForBytesWritten(msecs: waitMsecs); |
774 | QTest::qSleep(ms: waitMsecs); |
775 | senderPort.waitForReadyRead(msecs: waitMsecs); |
776 | QCOMPARE(senderPort.bytesAvailable(), qint64(newlineArray.size())); |
777 | QCOMPARE(senderPort.readAll(), newlineArray); |
778 | } |
779 | |
780 | void tst_QSerialPort::synchronousReadWrite() |
781 | { |
782 | QSerialPort senderPort(m_senderPortName); |
783 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
784 | |
785 | QSerialPort receiverPort(m_receiverPortName); |
786 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
787 | |
788 | QByteArray writeData; |
789 | for (int i = 0; i < 1024; ++i) |
790 | writeData.append(c: static_cast<char>(i)); |
791 | |
792 | senderPort.write(data: writeData); |
793 | senderPort.waitForBytesWritten(msecs: -1); |
794 | |
795 | QByteArray readData; |
796 | while ((readData.size() < writeData.size()) && receiverPort.waitForReadyRead(msecs: 100)) |
797 | readData.append(a: receiverPort.readAll()); |
798 | |
799 | QCOMPARE(readData, writeData); |
800 | } |
801 | |
802 | class AsyncReader : public QObject |
803 | { |
804 | Q_OBJECT |
805 | public: |
806 | explicit AsyncReader(QSerialPort &port, Qt::ConnectionType connectionType, int expectedBytesCount) |
807 | : serialPort(port), expectedBytesCount(expectedBytesCount) |
808 | { |
809 | connect(sender: &serialPort, signal: &QSerialPort::readyRead, receiver: this, slot: &AsyncReader::receive, type: connectionType); |
810 | } |
811 | |
812 | private slots: |
813 | void receive() |
814 | { |
815 | if (serialPort.bytesAvailable() < expectedBytesCount) |
816 | return; |
817 | tst_QSerialPort::exitLoop(); |
818 | } |
819 | |
820 | private: |
821 | QSerialPort &serialPort; |
822 | const int expectedBytesCount; |
823 | }; |
824 | |
825 | class AsyncWriterByBytesWritten : public QObject |
826 | { |
827 | Q_OBJECT |
828 | public: |
829 | explicit AsyncWriterByBytesWritten( |
830 | QSerialPort &port, Qt::ConnectionType connectionType, const QByteArray &dataToWrite) |
831 | : serialPort(port), writeChunkSize(0) |
832 | { |
833 | writeBuffer.setData(dataToWrite); |
834 | writeBuffer.open(openMode: QIODevice::ReadOnly); |
835 | connect(sender: &serialPort, signal: &QSerialPort::bytesWritten, receiver: this, slot: &AsyncWriterByBytesWritten::send, type: connectionType); |
836 | send(); |
837 | } |
838 | |
839 | private slots: |
840 | void send() |
841 | { |
842 | if (writeBuffer.bytesAvailable() > 0) |
843 | serialPort.write(data: writeBuffer.read(maxlen: ++writeChunkSize)); |
844 | } |
845 | |
846 | private: |
847 | QSerialPort &serialPort; |
848 | QBuffer writeBuffer; |
849 | int writeChunkSize; |
850 | }; |
851 | |
852 | void tst_QSerialPort::asynchronousWriteByBytesWritten_data() |
853 | { |
854 | QTest::addColumn<Qt::ConnectionType>(name: "readConnectionType" ); |
855 | QTest::addColumn<Qt::ConnectionType>(name: "writeConnectionType" ); |
856 | |
857 | QTest::newRow(dataTag: "BothQueued" ) << Qt::QueuedConnection << Qt::QueuedConnection; |
858 | QTest::newRow(dataTag: "BothDirect" ) << Qt::DirectConnection << Qt::DirectConnection; |
859 | QTest::newRow(dataTag: "ReadDirectWriteQueued" ) << Qt::DirectConnection << Qt::QueuedConnection; |
860 | QTest::newRow(dataTag: "ReadQueuedWriteDirect" ) << Qt::QueuedConnection << Qt::DirectConnection; |
861 | } |
862 | |
863 | void tst_QSerialPort::asynchronousWriteByBytesWritten() |
864 | { |
865 | QFETCH(Qt::ConnectionType, readConnectionType); |
866 | QFETCH(Qt::ConnectionType, writeConnectionType); |
867 | |
868 | QSerialPort receiverPort(m_receiverPortName); |
869 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
870 | AsyncReader reader(receiverPort, readConnectionType, alphabetArray.size()); |
871 | |
872 | QSerialPort senderPort(m_senderPortName); |
873 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
874 | AsyncWriterByBytesWritten writer(senderPort, writeConnectionType, alphabetArray); |
875 | |
876 | enterLoop(secs: 1); |
877 | QVERIFY2(!timeout(), "Timed out when waiting for the read or write." ); |
878 | QCOMPARE(receiverPort.bytesAvailable(), qint64(alphabetArray.size())); |
879 | QCOMPARE(receiverPort.readAll(), alphabetArray); |
880 | } |
881 | |
882 | class AsyncWriterByTimer : public QObject |
883 | { |
884 | Q_OBJECT |
885 | public: |
886 | explicit AsyncWriterByTimer( |
887 | QSerialPort &port, Qt::ConnectionType connectionType, const QByteArray &dataToWrite) |
888 | : serialPort(port), writeChunkSize(0) |
889 | { |
890 | writeBuffer.setData(dataToWrite); |
891 | writeBuffer.open(openMode: QIODevice::ReadOnly); |
892 | connect(sender: &timer, signal: &QTimer::timeout, receiver: this, slot: &AsyncWriterByTimer::send, type: connectionType); |
893 | timer.start(msec: 0); |
894 | } |
895 | |
896 | private slots: |
897 | void send() |
898 | { |
899 | if (writeBuffer.bytesAvailable() > 0) |
900 | serialPort.write(data: writeBuffer.read(maxlen: ++writeChunkSize)); |
901 | else |
902 | timer.stop(); |
903 | } |
904 | |
905 | private: |
906 | QSerialPort &serialPort; |
907 | QBuffer writeBuffer; |
908 | int writeChunkSize; |
909 | QTimer timer; |
910 | }; |
911 | |
912 | void tst_QSerialPort::asynchronousWriteByTimer_data() |
913 | { |
914 | QTest::addColumn<Qt::ConnectionType>(name: "readConnectionType" ); |
915 | QTest::addColumn<Qt::ConnectionType>(name: "writeConnectionType" ); |
916 | |
917 | QTest::newRow(dataTag: "BothQueued" ) << Qt::QueuedConnection << Qt::QueuedConnection; |
918 | QTest::newRow(dataTag: "BothDirect" ) << Qt::DirectConnection << Qt::DirectConnection; |
919 | QTest::newRow(dataTag: "ReadDirectWriteQueued" ) << Qt::DirectConnection << Qt::QueuedConnection; |
920 | QTest::newRow(dataTag: "ReadQueuedWriteDirect" ) << Qt::QueuedConnection << Qt::DirectConnection; |
921 | } |
922 | |
923 | void tst_QSerialPort::asynchronousWriteByTimer() |
924 | { |
925 | QFETCH(Qt::ConnectionType, readConnectionType); |
926 | QFETCH(Qt::ConnectionType, writeConnectionType); |
927 | |
928 | QSerialPort receiverPort(m_receiverPortName); |
929 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
930 | AsyncReader reader(receiverPort, readConnectionType, alphabetArray.size()); |
931 | |
932 | QSerialPort senderPort(m_senderPortName); |
933 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
934 | AsyncWriterByTimer writer(senderPort, writeConnectionType, alphabetArray); |
935 | |
936 | enterLoop(secs: 1); |
937 | QVERIFY2(!timeout(), "Timed out when waiting for the read or write." ); |
938 | QCOMPARE(receiverPort.bytesAvailable(), qint64(alphabetArray.size())); |
939 | QCOMPARE(receiverPort.readAll(), alphabetArray); |
940 | } |
941 | |
942 | class AsyncReader2 : public QObject |
943 | { |
944 | Q_OBJECT |
945 | public: |
946 | explicit AsyncReader2(QSerialPort &port, const QByteArray &expectedData) |
947 | : serialPort(port), expectedData(expectedData) |
948 | { |
949 | connect(sender: &serialPort, signal: &QSerialPort::readyRead, receiver: this, slot: &AsyncReader2::receive); |
950 | } |
951 | |
952 | private slots: |
953 | void receive() |
954 | { |
955 | receivedData.append(a: serialPort.readAll()); |
956 | if (receivedData == expectedData) |
957 | tst_QSerialPort::exitLoop(); |
958 | } |
959 | |
960 | private: |
961 | QSerialPort &serialPort; |
962 | const QByteArray expectedData; |
963 | QByteArray receivedData; |
964 | }; |
965 | |
966 | void tst_QSerialPort::asyncReadWithLimitedReadBufferSize() |
967 | { |
968 | QSerialPort senderPort(m_senderPortName); |
969 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
970 | |
971 | QSerialPort receiverPort(m_receiverPortName); |
972 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
973 | |
974 | receiverPort.setReadBufferSize(1); |
975 | QCOMPARE(receiverPort.readBufferSize(), qint64(1)); |
976 | |
977 | AsyncReader2 reader(receiverPort, alphabetArray); |
978 | |
979 | QCOMPARE(senderPort.write(alphabetArray), qint64(alphabetArray.size())); |
980 | |
981 | enterLoop(secs: 1); |
982 | QVERIFY2(!timeout(), "Timed out when waiting for the read or write." ); |
983 | } |
984 | |
985 | void tst_QSerialPort::readBufferOverflow() |
986 | { |
987 | QSerialPort senderPort(m_senderPortName); |
988 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
989 | |
990 | QSerialPort receiverPort(m_receiverPortName); |
991 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
992 | |
993 | const int readBufferSize = alphabetArray.size() / 2; |
994 | receiverPort.setReadBufferSize(readBufferSize); |
995 | QCOMPARE(receiverPort.readBufferSize(), qint64(readBufferSize)); |
996 | |
997 | QCOMPARE(senderPort.write(alphabetArray), qint64(alphabetArray.size())); |
998 | QVERIFY2(senderPort.waitForBytesWritten(100), "Waiting for bytes written failed" ); |
999 | |
1000 | QByteArray readData; |
1001 | while (receiverPort.waitForReadyRead(msecs: 100)) { |
1002 | QVERIFY(receiverPort.bytesAvailable() > 0); |
1003 | readData += receiverPort.readAll(); |
1004 | } |
1005 | |
1006 | QCOMPARE(readData, alphabetArray); |
1007 | |
1008 | // No more bytes available |
1009 | QVERIFY(receiverPort.bytesAvailable() == 0); |
1010 | } |
1011 | |
1012 | void tst_QSerialPort::readAfterInputClear() |
1013 | { |
1014 | QSerialPort senderPort(m_senderPortName); |
1015 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
1016 | |
1017 | QSerialPort receiverPort(m_receiverPortName); |
1018 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
1019 | |
1020 | const int readBufferSize = alphabetArray.size() / 2; |
1021 | receiverPort.setReadBufferSize(readBufferSize); |
1022 | QCOMPARE(receiverPort.readBufferSize(), qint64(readBufferSize)); |
1023 | |
1024 | const int waitMsecs = 100; |
1025 | |
1026 | // First write more than read buffer size |
1027 | QCOMPARE(senderPort.write(alphabetArray), qint64(alphabetArray.size())); |
1028 | QVERIFY2(senderPort.waitForBytesWritten(waitMsecs), "Waiting for bytes written failed" ); |
1029 | |
1030 | // Wait for first part of data into read buffer |
1031 | while (receiverPort.waitForReadyRead(msecs: waitMsecs)); |
1032 | QCOMPARE(receiverPort.bytesAvailable(), qint64(readBufferSize)); |
1033 | // Wait for second part of data into driver's FIFO |
1034 | QTest::qSleep(ms: waitMsecs); |
1035 | |
1036 | QVERIFY(receiverPort.clear(QSerialPort::Input)); |
1037 | QCOMPARE(receiverPort.bytesAvailable(), qint64(0)); |
1038 | |
1039 | // Second write less than read buffer size |
1040 | QCOMPARE(senderPort.write(newlineArray), qint64(newlineArray.size())); |
1041 | QVERIFY2(senderPort.waitForBytesWritten(waitMsecs), "Waiting for bytes written failed" ); |
1042 | |
1043 | while (receiverPort.waitForReadyRead(msecs: waitMsecs)); |
1044 | QCOMPARE(receiverPort.bytesAvailable(), qint64(newlineArray.size())); |
1045 | QCOMPARE(receiverPort.readAll(), newlineArray); |
1046 | |
1047 | // No more bytes available |
1048 | QVERIFY(receiverPort.bytesAvailable() == 0); |
1049 | } |
1050 | |
1051 | class MasterTransactor : public QObject |
1052 | { |
1053 | Q_OBJECT |
1054 | public: |
1055 | explicit MasterTransactor(const QString &name) |
1056 | : serialPort(name) |
1057 | { |
1058 | } |
1059 | |
1060 | public slots: |
1061 | void open() |
1062 | { |
1063 | if (serialPort.open(mode: QSerialPort::ReadWrite)) { |
1064 | createAsynchronousConnection(); |
1065 | serialPort.write(data: "A" , len: 1); |
1066 | } |
1067 | } |
1068 | |
1069 | private slots: |
1070 | void synchronousTransaction() |
1071 | { |
1072 | serialPort.write(data: "B" , len: 1); |
1073 | if (serialPort.waitForBytesWritten(msecs: 100)) { |
1074 | if (serialPort.waitForReadyRead(msecs: 100)) |
1075 | tst_QSerialPort::exitLoop(); |
1076 | } |
1077 | } |
1078 | |
1079 | void transaction() |
1080 | { |
1081 | deleteAsyncronousConnection(); |
1082 | synchronousTransaction(); |
1083 | } |
1084 | |
1085 | private: |
1086 | void createAsynchronousConnection() |
1087 | { |
1088 | connect(sender: &serialPort, signal: &QSerialPort::readyRead, receiver: this, slot: &MasterTransactor::transaction); |
1089 | } |
1090 | |
1091 | void deleteAsyncronousConnection() |
1092 | { |
1093 | serialPort.disconnect(); |
1094 | } |
1095 | |
1096 | QSerialPort serialPort; |
1097 | }; |
1098 | |
1099 | class SlaveTransactor : public QObject |
1100 | { |
1101 | Q_OBJECT |
1102 | public: |
1103 | explicit SlaveTransactor(const QString &name) |
1104 | : serialPort(new QSerialPort(name, this)) |
1105 | { |
1106 | connect(sender: serialPort, signal: &QSerialPort::readyRead, receiver: this, slot: &SlaveTransactor::transaction); |
1107 | } |
1108 | |
1109 | public slots: |
1110 | void open() |
1111 | { |
1112 | if (serialPort->open(mode: QSerialPort::ReadWrite)) |
1113 | emit ready(); |
1114 | } |
1115 | |
1116 | signals: |
1117 | void ready(); |
1118 | |
1119 | private slots: |
1120 | void transaction() |
1121 | { |
1122 | serialPort->write(data: "Z" , len: 1); |
1123 | } |
1124 | |
1125 | private: |
1126 | QSerialPort *serialPort; |
1127 | }; |
1128 | |
1129 | void tst_QSerialPort::synchronousReadWriteAfterAsynchronousReadWrite() |
1130 | { |
1131 | MasterTransactor master(m_senderPortName); |
1132 | auto slave = new SlaveTransactor(m_receiverPortName); |
1133 | |
1134 | QThread thread; |
1135 | slave->moveToThread(thread: &thread); |
1136 | thread.start(); |
1137 | |
1138 | QObject::connect(sender: &thread, signal: &QThread::finished, receiver: slave, slot: &SlaveTransactor::deleteLater); |
1139 | QObject::connect(sender: slave, signal: &SlaveTransactor::ready, receiver: &master, slot: &MasterTransactor::open); |
1140 | |
1141 | QMetaObject::invokeMethod(obj: slave, member: "open" , type: Qt::QueuedConnection); |
1142 | |
1143 | tst_QSerialPort::enterLoopMsecs(msecs: 2000); |
1144 | |
1145 | thread.quit(); |
1146 | thread.wait(); |
1147 | |
1148 | QVERIFY2(!timeout(), "Timed out when testing of transactions." ); |
1149 | } |
1150 | |
1151 | class BreakReader : public QObject |
1152 | { |
1153 | Q_OBJECT |
1154 | public: |
1155 | explicit BreakReader(QSerialPort &port) |
1156 | : serialPort(port) |
1157 | { |
1158 | connect(sender: &serialPort, signal: &QSerialPort::readyRead, receiver: this, slot: &BreakReader::receive); |
1159 | } |
1160 | |
1161 | private slots: |
1162 | void receive() |
1163 | { |
1164 | tst_QSerialPort::exitLoop(); |
1165 | } |
1166 | |
1167 | private: |
1168 | QSerialPort &serialPort; |
1169 | }; |
1170 | |
1171 | void tst_QSerialPort::controlBreak() |
1172 | { |
1173 | QSerialPort senderPort(m_senderPortName); |
1174 | QVERIFY(senderPort.open(QSerialPort::WriteOnly)); |
1175 | QCOMPARE(senderPort.isBreakEnabled(), false); |
1176 | |
1177 | QSignalSpy breakSpy(&senderPort, &QSerialPort::breakEnabledChanged); |
1178 | QVERIFY(breakSpy.isValid()); |
1179 | |
1180 | QSerialPort receiverPort(m_receiverPortName); |
1181 | QVERIFY(receiverPort.open(QSerialPort::ReadOnly)); |
1182 | |
1183 | BreakReader reader(receiverPort); |
1184 | |
1185 | QVERIFY(senderPort.setBreakEnabled(true)); |
1186 | QCOMPARE(senderPort.isBreakEnabled(), true); |
1187 | |
1188 | enterLoop(secs: 1); |
1189 | QVERIFY2(!timeout(), "Timed out when waiting for the read of break state." ); |
1190 | QVERIFY(receiverPort.bytesAvailable() > 0); |
1191 | |
1192 | const QByteArray actual = receiverPort.readAll(); |
1193 | const QByteArray expected(actual.size(), '\0'); |
1194 | QCOMPARE(actual, expected); |
1195 | |
1196 | QVERIFY(senderPort.setBreakEnabled(false)); |
1197 | QCOMPARE(senderPort.isBreakEnabled(), false); |
1198 | |
1199 | QCOMPARE(breakSpy.count(), 2); |
1200 | QCOMPARE(qvariant_cast<bool>(breakSpy.at(0).at(0)), true); |
1201 | QCOMPARE(qvariant_cast<bool>(breakSpy.at(1).at(0)), false); |
1202 | } |
1203 | |
1204 | void tst_QSerialPort::clearAfterOpen() |
1205 | { |
1206 | QSerialPort senderPort(m_senderPortName); |
1207 | QVERIFY(senderPort.open(QSerialPort::ReadWrite)); |
1208 | QCOMPARE(senderPort.error(), QSerialPort::NoError); |
1209 | QVERIFY(senderPort.clear()); |
1210 | QCOMPARE(senderPort.error(), QSerialPort::NoError); |
1211 | } |
1212 | |
1213 | void tst_QSerialPort::readWriteWithDifferentBaudRate_data() |
1214 | { |
1215 | QTest::addColumn<int>(name: "senderBaudRate" ); |
1216 | QTest::addColumn<int>(name: "receiverBaudRate" ); |
1217 | QTest::addColumn<bool>(name: "expectedResult" ); |
1218 | |
1219 | QTest::newRow(dataTag: "9600, 9600" ) << 9600 << 9600 << true; |
1220 | QTest::newRow(dataTag: "115200, 115200" ) << 115200 << 115200 << true; |
1221 | QTest::newRow(dataTag: "9600, 115200" ) << 9600 << 115200 << false; |
1222 | |
1223 | QTest::newRow(dataTag: "31250, 31250" ) << 31250 << 31250 << true; // custom baudrate (MIDI) |
1224 | QTest::newRow(dataTag: "31250, 115200" ) << 31250 << 115200 << false; |
1225 | |
1226 | #ifdef Q_OS_LINUX |
1227 | QTest::newRow(dataTag: "14400, 14400" ) << 14400 << 14400 << true; // custom baudrate for Linux |
1228 | QTest::newRow(dataTag: "14400, 115200" ) << 14400 << 115200 << false; |
1229 | #endif |
1230 | } |
1231 | |
1232 | void tst_QSerialPort::readWriteWithDifferentBaudRate() |
1233 | { |
1234 | QFETCH(int, senderBaudRate); |
1235 | QFETCH(int, receiverBaudRate); |
1236 | QFETCH(bool, expectedResult); |
1237 | |
1238 | { |
1239 | // setup before opening |
1240 | QSerialPort senderSerialPort(m_senderPortName); |
1241 | QVERIFY(senderSerialPort.setBaudRate(senderBaudRate)); |
1242 | QCOMPARE(senderSerialPort.baudRate(), senderBaudRate); |
1243 | QVERIFY(senderSerialPort.open(QSerialPort::ReadWrite)); |
1244 | QSerialPort receiverSerialPort(m_receiverPortName); |
1245 | QVERIFY(receiverSerialPort.setBaudRate(receiverBaudRate)); |
1246 | QCOMPARE(receiverSerialPort.baudRate(), receiverBaudRate); |
1247 | QVERIFY(receiverSerialPort.open(QSerialPort::ReadWrite)); |
1248 | |
1249 | QCOMPARE(senderSerialPort.write(alphabetArray), qint64(alphabetArray.size())); |
1250 | QVERIFY(senderSerialPort.waitForBytesWritten(500)); |
1251 | |
1252 | do { |
1253 | QVERIFY(receiverSerialPort.waitForReadyRead(500)); |
1254 | } while (receiverSerialPort.bytesAvailable() < alphabetArray.size()); |
1255 | |
1256 | if (expectedResult) |
1257 | QVERIFY(receiverSerialPort.readAll() == alphabetArray); |
1258 | else |
1259 | QVERIFY(receiverSerialPort.readAll() != alphabetArray); |
1260 | } |
1261 | |
1262 | { |
1263 | // setup after opening |
1264 | QSerialPort senderSerialPort(m_senderPortName); |
1265 | QVERIFY(senderSerialPort.open(QSerialPort::ReadWrite)); |
1266 | QVERIFY(senderSerialPort.setBaudRate(senderBaudRate)); |
1267 | QCOMPARE(senderSerialPort.baudRate(), senderBaudRate); |
1268 | QSerialPort receiverSerialPort(m_receiverPortName); |
1269 | QVERIFY(receiverSerialPort.open(QSerialPort::ReadWrite)); |
1270 | QVERIFY(receiverSerialPort.setBaudRate(receiverBaudRate)); |
1271 | QCOMPARE(receiverSerialPort.baudRate(), receiverBaudRate); |
1272 | |
1273 | QCOMPARE(senderSerialPort.write(alphabetArray), qint64(alphabetArray.size())); |
1274 | QVERIFY(senderSerialPort.waitForBytesWritten(500)); |
1275 | |
1276 | do { |
1277 | QVERIFY(receiverSerialPort.waitForReadyRead(500)); |
1278 | } while (receiverSerialPort.bytesAvailable() < alphabetArray.size()); |
1279 | |
1280 | if (expectedResult) |
1281 | QVERIFY(receiverSerialPort.readAll() == alphabetArray); |
1282 | else |
1283 | QVERIFY(receiverSerialPort.readAll() != alphabetArray); |
1284 | } |
1285 | } |
1286 | |
1287 | QTEST_MAIN(tst_QSerialPort) |
1288 | #include "tst_qserialport.moc" |
1289 | |