diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2015-09-05 12:43:05 +0300 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2015-09-07 18:32:32 +0000 |
commit | 841adec3d196f6dde50ff89585483950493ac113 (patch) | |
tree | 56b1ea8c35f6a0b7d4901942a1adb7c0a453edc4 | |
parent | 6eab15d551de3643c71cbf2028aa84300cd9dcc6 (diff) | |
download | qtserialport-841adec3d196f6dde50ff89585483950493ac113.tar.gz |
Refactor the speed configuration for *nix
The internal implementation of this is a little tangled. It is
reasonable to simplify it:
1. Remove the setBaudRate_helper() method, as it is equivalent to
setStandardBaudRate() method.
2. Now the setStandardBaudRate() and the setCustomBaudRate() are
self-sufficient methods (can setup a speed and an error codes
internally) and return a boolean values.
Also added the "loopback" test for check of different speeds.
Tested with the on-board and the USB serial ports.
(cherry-picked from 3abd3ed07d2b30ecb2f8b9772ed5b3811bb9194b)
Change-Id: I4320c2e29ad42a394e07753cbaea804d0faf6b78
Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 144 | ||||
-rw-r--r-- | src/serialport/qserialport_unix_p.h | 8 | ||||
-rw-r--r-- | tests/auto/qserialport/tst_qserialport.cpp | 48 |
3 files changed, 110 insertions, 90 deletions
diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 574bfc5..024f05b 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -427,121 +427,111 @@ bool QSerialPortPrivate::setBaudRate() && setBaudRate(outputBaudRate, QSerialPort::Output)); } -QSerialPortErrorInfo -QSerialPortPrivate::setBaudRate_helper(qint32 baudRate, - QSerialPort::Directions directions) +bool QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions) { - if ((directions & QSerialPort::Input) && ::cfsetispeed(¤tTermios, baudRate) < 0) - return getSystemError(); - - if ((directions & QSerialPort::Output) && ::cfsetospeed(¤tTermios, baudRate) < 0) - return getSystemError(); - - return QSerialPortErrorInfo(QSerialPort::NoError); -} - -#if defined(Q_OS_LINUX) - -QSerialPortErrorInfo -QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions) -{ - struct serial_struct currentSerialInfo; - - ::memset(¤tSerialInfo, 0, sizeof(currentSerialInfo)); - - if ((::ioctl(descriptor, TIOCGSERIAL, ¤tSerialInfo) != -1) - && (currentSerialInfo.flags & ASYNC_SPD_CUST)) { - currentSerialInfo.flags &= ~ASYNC_SPD_CUST; - currentSerialInfo.custom_divisor = 0; - if (::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) == -1) - return getSystemError(); +#ifdef Q_OS_LINUX + // try to clear custom baud rate + struct serial_struct serial; + ::memset(&serial, 0, sizeof(serial)); + if (::ioctl(descriptor, TIOCGSERIAL, &serial) != -1) { + if (serial.flags & ASYNC_SPD_CUST) { + serial.flags &= ~ASYNC_SPD_CUST; + serial.custom_divisor = 0; + // we don't check on errors because a driver can has not this feature + ::ioctl(descriptor, TIOCSSERIAL, &serial); + } } +#endif - return setBaudRate_helper(baudRate, directions); -} + if ((directions & QSerialPort::Input) && ::cfsetispeed(¤tTermios, baudRate) < 0) { + setError(getSystemError()); + return false; + } -#else + if ((directions & QSerialPort::Output) && ::cfsetospeed(¤tTermios, baudRate) < 0) { + setError(getSystemError()); + return false; + } -QSerialPortErrorInfo -QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions) -{ - return setBaudRate_helper(baudRate, directions); + return updateTermios(); } -#endif - #if defined(Q_OS_LINUX) -QSerialPortErrorInfo -QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) +bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { - Q_UNUSED(directions); + struct serial_struct serial; - struct serial_struct currentSerialInfo; - - ::memset(¤tSerialInfo, 0, sizeof(currentSerialInfo)); - - if (::ioctl(descriptor, TIOCGSERIAL, ¤tSerialInfo) == -1) - return getSystemError(); + if (::ioctl(descriptor, TIOCGSERIAL, &serial) == -1) { + setError(getSystemError()); + return false; + } - currentSerialInfo.flags &= ~ASYNC_SPD_MASK; - currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); - currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baudRate; + serial.flags &= ~ASYNC_SPD_MASK; + serial.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/); + serial.custom_divisor = serial.baud_base / baudRate; - if (currentSerialInfo.custom_divisor == 0) - return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("No suitable custom baud rate divisor")); + if (serial.custom_divisor == 0) { + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, + QSerialPort::tr("No suitable custom baud rate divisor"))); + return false; + } - if (currentSerialInfo.custom_divisor * baudRate != currentSerialInfo.baud_base) { + if (serial.custom_divisor * baudRate != serial.baud_base) { qWarning("Baud rate of serial port %s is set to %d instead of %d: divisor %f unsupported", qPrintable(systemLocation), - currentSerialInfo.baud_base / currentSerialInfo.custom_divisor, - baudRate, (float)currentSerialInfo.baud_base / baudRate); + serial.baud_base / serial.custom_divisor, + baudRate, (float)serial.baud_base / baudRate); } - if (::ioctl(descriptor, TIOCSSERIAL, ¤tSerialInfo) == -1) - return getSystemError(); + if (::ioctl(descriptor, TIOCSSERIAL, &serial) == -1) { + setError(getSystemError()); + return false; + } - return setBaudRate_helper(B38400, directions); + return setStandardBaudRate(B38400, directions); } #elif defined(Q_OS_MAC) -QSerialPortErrorInfo -QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) +bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(directions); -#if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) - if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) == -1) - return getSystemError(); - - return QSerialPortErrorInfo(QSerialPort::NoError); +#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) + if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) == -1) { + setError(getSystemError()); + return false; + } + return true; +#else + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, + QSerialPort::tr("Custom baud rate is not supported"))); + return false; #endif - - return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate is not supported")); } #elif defined (Q_OS_QNX) -QSerialPortErrorInfo -QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) +bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { // On QNX, the values of the 'Bxxxx' constants are set to 'xxxx' (i.e. // B115200 is defined to '115200'), which means that literal values can be // passed to cfsetispeed/cfsetospeed, including custom values, provided // that the underlying hardware supports them. - return setBaudRate_helper(baudRate, directions); + return setStandardBaudRate(baudRate, directions); } #else -QSerialPortErrorInfo -QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) +bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions) { Q_UNUSED(baudRate); Q_UNUSED(directions); - return QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError); + setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, + QSerialPort::tr("Custom baud rate is not supported"))); + return false; } #endif @@ -555,15 +545,9 @@ bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions di const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate); - const QSerialPortErrorInfo error = (unixBaudRate > 0) - ? setStandardBaudRate(unixBaudRate, directions) - : setCustomBaudRate(baudRate, directions); - - if (error.errorCode == QSerialPort::NoError) - return updateTermios(); - - setError(error); - return false; + return (unixBaudRate > 0) + ? setStandardBaudRate(unixBaudRate, directions) + : setCustomBaudRate(baudRate, directions); } bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits) diff --git a/src/serialport/qserialport_unix_p.h b/src/serialport/qserialport_unix_p.h index 8ffb0c5..353592b 100644 --- a/src/serialport/qserialport_unix_p.h +++ b/src/serialport/qserialport_unix_p.h @@ -165,12 +165,8 @@ private: bool initialize(QIODevice::OpenMode mode); bool updateTermios(); - QSerialPortErrorInfo setBaudRate_helper(qint32 baudRate, - QSerialPort::Directions directions); - QSerialPortErrorInfo setCustomBaudRate(qint32 baudRate, - QSerialPort::Directions directions); - QSerialPortErrorInfo setStandardBaudRate(qint32 baudRate, - QSerialPort::Directions directions); + bool setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions); + bool setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions); QSerialPortErrorInfo getSystemError(int systemErrorCode = -1) const; bool isReadNotificationEnabled() const; diff --git a/tests/auto/qserialport/tst_qserialport.cpp b/tests/auto/qserialport/tst_qserialport.cpp index 66c7447..a245fa4 100644 --- a/tests/auto/qserialport/tst_qserialport.cpp +++ b/tests/auto/qserialport/tst_qserialport.cpp @@ -119,14 +119,17 @@ private slots: void controlBreak(); + void clearAfterOpen(); + + void loopBack_data(); + void loopBack(); + protected slots: void handleBytesWrittenAndExitLoopSlot(qint64 bytesWritten); void handleBytesWrittenAndExitLoopSlot2(qint64 bytesWritten); private: -#ifdef Q_OS_WIN void clearReceiver(const QString &customReceiverName = QString()); -#endif QString m_senderPortName; QString m_receiverPortName; @@ -146,7 +149,6 @@ tst_QSerialPort::tst_QSerialPort() { } -#ifdef Q_OS_WIN // This method is a workaround for the "com0com" virtual serial port // driver, which is installed on CI. The problem is that the close/clear // methods have no effect on sender serial port. If any data didn't manage @@ -164,7 +166,6 @@ void tst_QSerialPort::clearReceiver(const QString &customReceiverName) if (receiver.open(QIODevice::ReadOnly)) enterLoopMsecs(100); } -#endif void tst_QSerialPort::initTestCase() { @@ -908,5 +909,44 @@ void tst_QSerialPort::controlBreak() QCOMPARE(qvariant_cast<bool>(breakSpy.at(1).at(0)), false); } +void tst_QSerialPort::clearAfterOpen() +{ + QSerialPort senderPort(m_senderPortName); + QVERIFY(senderPort.open(QSerialPort::ReadWrite)); + QCOMPARE(senderPort.error(), QSerialPort::NoError); + QVERIFY(senderPort.clear()); + QCOMPARE(senderPort.error(), QSerialPort::NoError); +} + +void tst_QSerialPort::loopBack_data() +{ + QTest::addColumn<int>("baudRate"); + + QTest::newRow("9600 N 1 None") << 9600; + QTest::newRow("115200 N 1 None") << 115200; + QTest::newRow("14400 N 1 None") << 14400; +} + +// This test works with the connected Rx and Tx pins. +void tst_QSerialPort::loopBack() +{ + QFETCH(int, baudRate); + + QSerialPort serialPort(m_senderPortName); + QVERIFY(serialPort.open(QSerialPort::ReadWrite)); + + QVERIFY(serialPort.setBaudRate(baudRate)); + QCOMPARE(serialPort.baudRate(), baudRate); + + QCOMPARE(serialPort.write(alphabetArray), qint64(alphabetArray.size())); + QVERIFY(serialPort.waitForBytesWritten(500)); + + do { + QVERIFY(serialPort.waitForReadyRead(500)); + } while (serialPort.bytesAvailable() < alphabetArray.size()); + + QCOMPARE(serialPort.readAll(), alphabetArray); +} + QTEST_MAIN(tst_QSerialPort) #include "tst_qserialport.moc" |