diff options
author | Alex Henrie <alexhenrie24@gmail.com> | 2013-07-01 23:51:18 -0600 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-07-03 01:46:13 +0200 |
commit | 4c67500e5d14e561e37b4bdc056f059d3eefdfa4 (patch) | |
tree | 26d6532dc08bf3d75dea1764d08046fff13010a6 | |
parent | 4464dfccc8480146744ec1b02aedb41d0fb3ec1b (diff) | |
download | qtserialport-4c67500e5d14e561e37b4bdc056f059d3eefdfa4.tar.gz |
Add property to set exclusivity
Disabling the serial port driver's exclusive mode is necessary for
pseudo serial ports and some USB/serial adapters to work correctly.
Change-Id: I74d45feed619817b61e265b00aec8b0ebfae7a33
Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r-- | src/serialport/qserialport.cpp | 44 | ||||
-rw-r--r-- | src/serialport/qserialport.h | 15 | ||||
-rw-r--r-- | src/serialport/qserialport_p.h | 1 | ||||
-rw-r--r-- | src/serialport/qserialport_symbian.cpp | 6 | ||||
-rw-r--r-- | src/serialport/qserialport_symbian_p.h | 1 | ||||
-rw-r--r-- | src/serialport/qserialport_unix.cpp | 76 | ||||
-rw-r--r-- | src/serialport/qserialport_unix_p.h | 3 | ||||
-rw-r--r-- | src/serialport/qserialport_win.cpp | 6 | ||||
-rw-r--r-- | src/serialport/qserialport_win_p.h | 1 |
9 files changed, 129 insertions, 24 deletions
diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 96f06d4..d90b48d 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -73,6 +73,7 @@ QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q) , stopBits(QSerialPort::UnknownStopBits) , flow(QSerialPort::UnknownFlowControl) , policy(QSerialPort::IgnorePolicy) + , exclusiveMode(QSerialPort::FullyExclusive) , settingsRestoredOnClose(true) , q_ptr(q) { @@ -320,6 +321,27 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \sa QSerialPort::error */ +/*! + \enum QSerialPort::ExclusiveModeFlag + + This enum describes the level of exclusivity to set on the serial port. + + \value NotExclusive The serial port may be opened elsewhere even if it + is open here. This flag only has effect on Unix. + \value LockFileExclusive A lock file prevents the serial port from being + opened elsewhere while it is open here. This flag + only has effect on Unix. + \value DriverExclusive The serial port driver prevents the serial port + from being opened elsewhere while it is open here. + This flag only has effect on Unix if the ioctl + request TIOCEXCL is available. + \value FullyExclusive Both the serial port driver and, if on Unix, a + lock file prevent the serial port from being opened + elsewhere while it is open here. + + \sa QSerialPort::exclusiveMode +*/ + /*! @@ -489,6 +511,28 @@ void QSerialPort::close() } /*! + \property QSerialPort::exclusiveMode + \brief the exclusivity of this object's claim on the serial port + + If the setting is successful, returns true; otherwise returns false. Serial + ports are set to QSerialPort::FullyExclusive by default. + + This flag is always QSerialPort::FullyExclusive on Windows and Symbian and + cannot be changed. +*/ +bool QSerialPort::setExclusiveMode(ExclusiveMode exclusiveMode) +{ + Q_D(QSerialPort); + return d->setExclusiveMode(exclusiveMode); +} + +QSerialPort::ExclusiveMode QSerialPort::exclusiveMode() const +{ + Q_D(const QSerialPort); + return d->exclusiveMode; +} + +/*! \property QSerialPort::settingsRestoredOnClose \brief the flag which allows to restore the previous settings while closing the serial port. diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index c193bcd..6ec8e25 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -65,10 +65,11 @@ class Q_SERIALPORT_EXPORT QSerialPort : public QIODevice Q_PROPERTY(bool dataTerminalReady READ isDataTerminalReady WRITE setDataTerminalReady NOTIFY dataTerminalReadyChanged) Q_PROPERTY(bool requestToSend READ isRequestToSend WRITE setRequestToSend NOTIFY requestToSendChanged) Q_PROPERTY(SerialPortError error READ error RESET clearError NOTIFY error) + Q_PROPERTY(ExclusiveMode exclusiveMode READ exclusiveMode WRITE setExclusiveMode) Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged) Q_ENUMS(BaudRate DataBits Parity StopBits FlowControl DataErrorPolicy SerialPortError) - Q_FLAGS(Directions PinoutSignals) + Q_FLAGS(Directions PinoutSignals ExclusiveMode) public: @@ -160,6 +161,14 @@ public: UnknownError }; + enum ExclusiveModeFlag { + NotExclusive = 0, + LockFileExclusive = 1, + DriverExclusive = 2, + FullyExclusive = LockFileExclusive | DriverExclusive + }; + Q_DECLARE_FLAGS(ExclusiveMode, ExclusiveModeFlag) + explicit QSerialPort(QObject *parent = 0); explicit QSerialPort(const QString &name, QObject *parent = 0); explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = 0); @@ -173,6 +182,9 @@ public: bool open(OpenMode mode) Q_DECL_OVERRIDE; void close() Q_DECL_OVERRIDE; + bool setExclusiveMode(ExclusiveMode exclusiveMode); + ExclusiveMode exclusiveMode() const; + void setSettingsRestoredOnClose(bool restore); bool settingsRestoredOnClose() const; @@ -252,6 +264,7 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions) Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals) +Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::ExclusiveMode) QT_END_NAMESPACE diff --git a/src/serialport/qserialport_p.h b/src/serialport/qserialport_p.h index abd9cb6..b74cda6 100644 --- a/src/serialport/qserialport_p.h +++ b/src/serialport/qserialport_p.h @@ -80,6 +80,7 @@ public: QSerialPort::DataErrorPolicy policy; bool dataTerminalReady; bool requestToSend; + QSerialPort::ExclusiveMode exclusiveMode; bool settingsRestoredOnClose; QSerialPort * const q_ptr; }; diff --git a/src/serialport/qserialport_symbian.cpp b/src/serialport/qserialport_symbian.cpp index 2bba5a4..3e904ab 100644 --- a/src/serialport/qserialport_symbian.cpp +++ b/src/serialport/qserialport_symbian.cpp @@ -158,6 +158,12 @@ void QSerialPortPrivate::close() descriptor.Close(); } +bool QSerialPortPrivate::setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode) +{ + Q_UNUSED(exclusiveMode); + return false; +} + QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const { QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; diff --git a/src/serialport/qserialport_symbian_p.h b/src/serialport/qserialport_symbian_p.h index 7f9eadd..1b235f5 100644 --- a/src/serialport/qserialport_symbian_p.h +++ b/src/serialport/qserialport_symbian_p.h @@ -84,6 +84,7 @@ public: bool setStopBits(QSerialPort::StopBits stopBits); bool setFlowControl(QSerialPort::FlowControl flowControl); bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + bool setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode); bool notifyRead(); bool notifyWrite(); diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index 2f6c8cc..0e19d05 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -139,11 +139,7 @@ QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { - QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); - const char *ptr = portName.constData(); - - bool byCurrPid = false; - if (QTtyLocker::isLocked(ptr, &byCurrPid)) { + if (isLockedByFile()) { q_ptr->setError(QSerialPort::PermissionError); return false; } @@ -169,17 +165,13 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode) return false; } - ::fcntl(descriptor, F_SETFL, FNDELAY); - - QTtyLocker::lock(ptr); - if (!QTtyLocker::isLocked(ptr, &byCurrPid)) { + if (!changeExclusiveMode(exclusiveMode)) { + ::close(descriptor); q_ptr->setError(QSerialPort::PermissionError); return false; } -#ifdef TIOCEXCL - ::ioctl(descriptor, TIOCEXCL); -#endif + ::fcntl(descriptor, F_SETFL, FNDELAY); if (::tcgetattr(descriptor, &restoredTermios) == -1) { q_ptr->setError(decodeSystemError()); @@ -217,10 +209,6 @@ void QSerialPortPrivate::close() #endif } -#ifdef TIOCNXCL - ::ioctl(descriptor, TIOCNXCL); -#endif - if (readNotifier) { readNotifier->setEnabled(false); readNotifier->deleteLater(); @@ -239,19 +227,24 @@ void QSerialPortPrivate::close() exceptionNotifier = 0; } - ::close(descriptor); - - QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); - const char *ptr = portName.constData(); + changeExclusiveMode(QSerialPort::NotExclusive); - bool byCurrPid = false; - if (QTtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid) - QTtyLocker::unlock(ptr); + ::close(descriptor); descriptor = -1; isCustomBaudRateSupported = false; } +bool QSerialPortPrivate::setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode) +{ + if (descriptor != -1 && !changeExclusiveMode(exclusiveMode)) { + q_ptr->setError(QSerialPort::PermissionError); + return false; + } + this->exclusiveMode = exclusiveMode; + return true; +} + QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const { int arg = 0; @@ -1340,4 +1333,41 @@ QList<qint32> QSerialPortPrivate::standardBaudRates() return standardBaudRateMap().keys(); } +bool QSerialPortPrivate::isLockedByFile() +{ + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + bool byCurrPid; + + return QTtyLocker::isLocked(ptr, &byCurrPid); +} + +bool QSerialPortPrivate::changeExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode) +{ + QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit(); + const char *ptr = portName.constData(); + bool byCurrPid; + + if (exclusiveMode & QSerialPort::LockFileExclusive) { + QTtyLocker::lock(ptr); + if (!QTtyLocker::isLocked(ptr, &byCurrPid)) + return false; + } else { + if (QTtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid) + QTtyLocker::unlock(ptr); + } + +#ifdef TIOCEXCL + if (exclusiveMode & QSerialPort::DriverExclusive) { + if (::ioctl(descriptor, TIOCEXCL) < 0) { + QTtyLocker::unlock(ptr); + return false; + } + } else + ::ioctl(descriptor, TIOCNXCL); +#endif + + return true; +} + QT_END_NAMESPACE diff --git a/src/serialport/qserialport_unix_p.h b/src/serialport/qserialport_unix_p.h index ce70c24..3d96ecb 100644 --- a/src/serialport/qserialport_unix_p.h +++ b/src/serialport/qserialport_unix_p.h @@ -91,6 +91,7 @@ public: bool setStopBits(QSerialPort::StopBits stopBits); bool setFlowControl(QSerialPort::FlowControl flow); bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + bool setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode); bool readNotification(); bool writeNotification(int maxSize = INT_MAX); @@ -149,6 +150,8 @@ private: #endif qint64 readPerChar(char *data, qint64 maxSize); + bool isLockedByFile(); + bool changeExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode); }; QT_END_NAMESPACE diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index e8d4d62..4da1d1d 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -310,6 +310,12 @@ void QSerialPortPrivate::close() #endif // #ifndef Q_OS_WINCE +bool QSerialPortPrivate::setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode) +{ + Q_UNUSED(exclusiveMode); + return false; +} + QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const { DWORD modemStat = 0; diff --git a/src/serialport/qserialport_win_p.h b/src/serialport/qserialport_win_p.h index a59ea9a..02810c0 100644 --- a/src/serialport/qserialport_win_p.h +++ b/src/serialport/qserialport_win_p.h @@ -97,6 +97,7 @@ public: bool setStopBits(QSerialPort::StopBits stopBits); bool setFlowControl(QSerialPort::FlowControl flowControl); bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy); + bool setExclusiveMode(QSerialPort::ExclusiveMode exclusiveMode); bool processIoErrors(bool error); #ifndef Q_OS_WINCE |