From 7a1f25496b6539f352a8a998014729ee69ef77ad Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Sat, 28 Sep 2013 00:57:30 +0100 Subject: Refactor the blocking master documentation Change-Id: I67e1eb66c5661f6830389189a323aa7f97e474f9 Reviewed-by: Denis Shienkov --- examples/serialport/doc/blockingmaster.qdoc | 135 ++++++++++++++-------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/examples/serialport/doc/blockingmaster.qdoc b/examples/serialport/doc/blockingmaster.qdoc index 1ce649a..32176a1 100644 --- a/examples/serialport/doc/blockingmaster.qdoc +++ b/examples/serialport/doc/blockingmaster.qdoc @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2011 - 2012 Denis Shienkov +** Copyright (C) 2012 - 2013 Laszlo Papp ** Contact: http://www.qt-project.org/legal ** ** This file is part of the documentation of the Qt Toolkit. @@ -29,40 +30,40 @@ \example blockingmaster \title Blocking Master Example \ingroup qtserialport-examples - \brief Explains how to create an app using QSerialPort's synchronous API. + \brief Explains how to use the synchronous API of QSerialPort. The blocking master example shows how to create an application for a - serial interface using QSerialPort's synchronous API in a worker thread. + serial interface using the synchronous API of QSerialPort in a worker + thread. \image blockingmaster-example.png Screenshot of the blocking master example - QSerialPort supports two general programming approaches: + QSerialPort supports two programming alternatives: \list - \li \e{The asynchronous (non-blocking) approach.} Operations are scheduled - and performed when the control returns to Qt's event loop. QSerialPort emits - a signal when the operation is finished. For example, QSerialPort::write() - returns immediately. When the data is sent to the serial port, QSerialPort - emits \l{QIODevice::bytesWritten()}{bytesWritten()}. + \li \e{The asynchronous (non-blocking) alternative.} Operations are scheduled + and performed when the control returns to the Qt event loop. The QSerialPort + class emits a signal when the operation is finished. For example, the + \l{QIODevice::write()}{write()} method returns immediately. When the data is + sent to the serial port, the QSerialPort class emits the + \l{QIODevice::bytesWritten()}{bytesWritten()} signal. - \li \e{The synchronous (blocking) approach.} In headless and multithreaded - applications, the wait functions can be called (in this case, - QSerialPort::waitForReadyRead()) to suspend the calling thread until the - operation has completed. + \li \e{The synchronous (blocking) alternative.} In headless and multithreaded + applications, the wait method can be called (in this case, + \l{QSerialPort::waitForReadyRead()}{waitForReadyRead()}) to suspend the + calling thread until the operation has completed. \endlist - In this example, the synchronous approach is demonstrated. The \l{terminal}{Terminal} - example illustrates the asynchronous approach. + In this example, the synchronous alternative is demonstrated. The + \l{terminal}{Terminal} example illustrates the asynchronous alternative. - The purpose of this example is to demonstrate a pattern that you can use - to simplify your serial programming code, without losing responsiveness - in your user interface. Use of Qt's blocking serial programming API often - leads to simpler code, but because of its blocking behavior, it should only - be used in non-GUI threads to prevent the user interface from freezing. - But contrary to what many think, using threads with QThread does not - necessarily add unmanagable complexity to your application. + The purpose of this example is to demonstrate how to simplify your serial + programming code without losing the responsiveness of the user interface. + The blocking serial programming API often leads to simpler code, but it + should only be used in non-GUI threads to keep the user interface + responsive. This application is the master which demonstrates the work paired with the slave application \l{blockingslave}{Blocking Slave Example}. @@ -70,55 +71,53 @@ The master application initiates the transfer request via the serial port to the slave application and waits for response. - We will start with the MasterThread class, which handles the serial - programming code. - \snippet blockingmaster/masterthread.h 0 - MasterThread is a QThread subclass that provides an API for scheduling - requests to the slave, and it has signals for delivering responses and reporting - errors. The transaction() method can be called to startup the new master - transaction with the desired request data and other parameters. The result - is delivered by the response() signal. If any error occurs, the error() or - timeout() signal is emitted. + MasterThread is a QThread subclass that provides API for scheduling + requests to the slave. This class provides signals for responding and + reporting errors. The transaction() method can be called to start up the + new master transaction with the desired request. The result is provided by + the response() signal. In case of any issues, the error() or timeout() + signal is emitted. - It's important to notice that the transaction() method is called from the main, - GUI thread, but the request data and other parameters will be accessed from - MasterThread's thread. Since the MasterThread data members will be read and - written concurrently from different threads, QMutex is used to synchronize - the access. + Note, the transaction() method is called in the main thread, but the + request is provided in the MasterThread thread. The MasterThread + data members are read and written concurrently in different threads, thus + the QMutex class is used to synchronize the access. \snippet blockingmaster/masterthread.cpp 2 - The transaction() function stores the serial port name, timeout and request - data. The mutex can be locked with QMutexLocker to protect this data. Then, - the thread can be started, unless it is already running. QWaitCondition::wakeOne() - will be discussed later. + The transaction() method stores the serial port name, timeout and request + data. The mutex can be locked with QMutexLocker to protect this data. The + thread can be started then, unless it is already running. The + \l{QWaitCondition::wakeOne()}{wakeOne()} method is discussed later. \snippet blockingmaster/masterthread.cpp 4 \snippet blockingmaster/masterthread.cpp 5 - In the run() function, start by acquiring the mutex lock, fetch the - serial port name, timeout and request data from the member data, and then - release the lock again. + In the run() function, the first is to lock the QMutex object, then fetch the + serial port name, timeout and request data by using the member data. Having + that done, the QMutex lock is released. - Under no circumstance should the method \c transaction() be called simultaneously - with a process fetching these data. QString is reentrant but not thread-safe, and - it is not recommended to read the serial port name from one request, - and timeout or request data from another. The MasterThread can only handle - one request at a time. + Under no circumstance should the \c transaction() method be called + simultaneously with a process fetching the data. Note, while the QString + class is reentrant, it is not thread-safe. Thereby, it is not recommended to + read the serial port name in a request thread, and timeout or request data + in another thread. The MasterThread class can only handle one request at a + time. - The QSerialPort object we construct on stack into run() function before loop - enter: + The QSerialPort object is constructed on stack in the run() method before + entering the loop: \snippet blockingmaster/masterthread.cpp 6 - This allows us once to create an object, while running the loop, and also means - that all the methods of the object will be executed in the context of the - run() thread. + This makes it possible to create an object while running the loop. It also + means that all the object methods are executed in the scope of the run() + method. - In the loop, check whether the name of the serial port for the current trans- - action has changed or not. If it has, reopen and reconfigure the serial port. + It is checked inside the loop whether or not the serial port name of the + current transaction has changed. If this has changed, the serial port is + reopened and then reconfigured. \snippet blockingmaster/masterthread.cpp 7 @@ -127,23 +126,27 @@ \snippet blockingmaster/masterthread.cpp 8 - \warning The method waitForBytesWritten() should be used after each write() - call for the blocking approach, because it processes all the I/O routines - instead of the Qt event loop. + \warning As for the blocking transfer, the + \l{QSerialPort::waitForBytesWritten()}{waitForBytesWritten()} method should be + used after each \l{QIODevice::write()}{write} method call. This will process all + the I/O routines instead of the Qt event loop. - The timeout() signal is emitted if an error occurs when transferring data. + The timeout() signal is emitted if a timeout error occurs when transferring + data. \snippet blockingmaster/masterthread.cpp 9 - After a successful request, wait for a response, and then try to read it. + There is a waiting period for response after a successful request, and then + it is read again. \snippet blockingmaster/masterthread.cpp 10 - \warning The method waitForReadyRead() should be used before each read() - call for the blocking approach, because it processes all the I/O routines - instead of Qt event loop. + \warning As for the blocking alternative, the + \l{QSerialPort::waitForReadyRead()}{waitForReadyRead()} method should be + used before each read() call. This will processes all the I/O routines + instead of the Qt event loop. - The timeout() signal is emitted if an error occurs when receiving data. + The timeout() signal is emitted if a timeout error occurs when receiving data. \snippet blockingmaster/masterthread.cpp 11 @@ -152,9 +155,9 @@ \snippet blockingmaster/masterthread.cpp 12 - Next, the thread goes to sleep until the next transaction has appeared. On - waking, the thread re-reads the new data from the members and runs the - loop from the beginning. + Afterwards, the thread goes to sleep until the next transaction appears. + The thread reads the new data after waking up by using the members and + runs the loop from the beginning. \snippet blockingmaster/masterthread.cpp 13 -- cgit v1.2.1 From 3309138e2574fa277eb3eb65ad26ab0836925f17 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Fri, 4 Oct 2013 00:57:57 +0100 Subject: Use the "\note" qdoc command instead of the raw "Note" term Change-Id: If9631df1be0a164140c95b52e8537fc849709ee9 Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 531dc39..fb427dc 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -184,8 +184,9 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \enum QSerialPort::BaudRate This enum describes the baud rate which the communication device operates - with. Note: only the most common standard baud rates are listed in this - enum. + with. + + \note Only the most common standard baud rates are listed in this enum. \value Baud1200 1200 baud. \value Baud2400 2400 baud. @@ -821,8 +822,8 @@ bool QSerialPort::isRequestToSend() desired signal by applying a mask "AND", where the mask is the desired enumeration value from QSerialPort::PinoutSignals. - Note that, this method performs a system call, thus ensuring that the line - signal states are returned properly. This is necessary when the underlying + \note This method performs a system call, thus ensuring that the line signal + states are returned properly. This is necessary when the underlying operating systems cannot provide proper notifications about the changes. \sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(), -- cgit v1.2.1 From 0eed986ec745828d38141d0568a9fc40f603b163 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Fri, 4 Oct 2013 00:07:53 +0100 Subject: Add a new error value called "NotOpenError" This error message is used when the serial port parameter setters are called even though the serial port is not open, and it should be. The details are very similar to the previously introduced TimeoutError, as in: 1) The "\since 5.2" notion has to be added manually as qdoc has no support for enumeration values in that regard. 2) The value itself has to be added at the end of the enumeration not to break the binary compatibility unnecessarily. It is fine as long as the error documentation for the end users can be kept in the order we wish to do. Each method documentation already contains the information that the error is set properly when that occurs, so this change can be considered as a bug fix rather than a new feature. It is a behavior change of course just as any bug fix. The previous operation was wrong to go ahead down to the syscalls even though the serial port was not open. Thereby, that was a bit pointless. Unfortunately, there is no similar error introduced for the existing QIODevice subclasses just yet, but this term is at least inline with the open mode of QIODevice which is "NotOpen". For sure, when the parameter setters are called by the end user without the device being open results false return value as per method documentation. This change was tested on Linux with Qt 4 and then 5. Change-Id: I1bc7309e34bdf59793f1de510866dae1bb48b539 Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++ src/serialport/qserialport.h | 3 ++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index fb427dc..34214af 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -306,6 +306,10 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) having enough permission and credentials to open. \value OpenError An error occurred while attempting to open an already opened device in this object. + \value NotOpenError This error occurs when an operation is executed + that can only be successfully performed if the + device is open. This value was introduced in + QtSerialPort 5.2. \value ParityError Parity error detected by the hardware while reading data. \value FramingError Framing error detected by the hardware while reading data. \value BreakConditionError Break condition detected by the hardware on @@ -544,6 +548,11 @@ bool QSerialPort::setBaudRate(qint32 baudRate, Directions directions) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (d->setBaudRate(baudRate, directions)) { if (directions & QSerialPort::Input) { if (d->inputBaudRate != baudRate) @@ -598,6 +607,11 @@ bool QSerialPort::setDataBits(DataBits dataBits) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (d->setDataBits(dataBits)) { if (d->dataBits != dataBits) { d->dataBits = dataBits; @@ -637,6 +651,11 @@ bool QSerialPort::setParity(Parity parity) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (d->setParity(parity)) { if (d->parity != parity) { d->parity = parity; @@ -675,6 +694,11 @@ bool QSerialPort::setStopBits(StopBits stopBits) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (d->setStopBits(stopBits)) { if (d->stopBits != stopBits) { d->stopBits = stopBits; @@ -713,6 +737,11 @@ bool QSerialPort::setFlowControl(FlowControl flow) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (d->setFlowControl(flow)) { if (d->flow != flow) { d->flow = flow; @@ -752,6 +781,11 @@ bool QSerialPort::setDataTerminalReady(bool set) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + bool retval = d->setDataTerminalReady(set); if (retval && (d->dataTerminalReady != set)) { d->dataTerminalReady = set; @@ -790,6 +824,11 @@ bool QSerialPort::setRequestToSend(bool set) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + bool retval = d->setRequestToSend(set); if (retval && (d->requestToSend != set)) { d->requestToSend = set; @@ -911,6 +950,11 @@ bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) { Q_D(QSerialPort); + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + const bool ret = d->policy == policy || d->setDataErrorPolicy(policy); if (ret && (d->policy != policy)) { d->policy = policy; diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index 781a98b..81a39fb 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -165,7 +165,8 @@ public: ResourceError, UnsupportedOperationError, UnknownError, - TimeoutError + TimeoutError, + NotOpenError }; explicit QSerialPort(QObject *parent = 0); -- cgit v1.2.1 From 1756c3d2af79888f89549851433914f627f7ef9d Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Fri, 4 Oct 2013 00:31:23 +0100 Subject: Fix a grammar issue of the open method documentation Change-Id: I158a5a66af5c07d4454a559d4e5d6b7a666f43a7 Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 34214af..acd634c 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -441,7 +441,7 @@ QString QSerialPort::portName() const \reimp Opens the serial port using OpenMode \a mode, and then returns true if - successful; otherwise returns false with and sets an error code which can be + successful; otherwise returns false and sets an error code which can be obtained by calling the error() method. \warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly, -- cgit v1.2.1 From cea259f0aafb87405073ac5800c1d5bbb5c7a113 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Fri, 4 Oct 2013 00:53:23 +0100 Subject: Document that the serial port parameters cannot be set before opening Task-number: QTBUG-33774 Change-Id: I21893547ff9debc3be9f972c77ce2a306fe60d7f Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index acd634c..602cf6a 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -444,6 +444,10 @@ QString QSerialPort::portName() const successful; otherwise returns false and sets an error code which can be obtained by calling the error() method. + \note This method has to be called before setting certain serial port + parameters. See each property documentation for details when it is + necessary. + \warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly, or QIODevice::ReadWrite. Other modes are unsupported. @@ -538,6 +542,13 @@ bool QSerialPort::settingsRestoredOnClose() const QSerialPort::error property. To set the baud rate, use the enumeration QSerialPort::BaudRate or any positive qint32 value. + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. + \warning Only the AllDirections flag is support for setting this property on Windows, Windows CE, and Symbian. @@ -602,6 +613,13 @@ qint32 QSerialPort::baudRate(Directions directions) const If the setting is successful, returns true; otherwise returns false and sets an error code which can be obtained by accessing the value of the QSerialPort::error property. + + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. */ bool QSerialPort::setDataBits(DataBits dataBits) { @@ -646,6 +664,13 @@ QSerialPort::DataBits QSerialPort::dataBits() const If the setting is successful, returns true; otherwise returns false and sets an error code which can be obtained by accessing the value of the QSerialPort::error property. + + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. */ bool QSerialPort::setParity(Parity parity) { @@ -689,6 +714,13 @@ QSerialPort::Parity QSerialPort::parity() const If the setting is successful, returns true; otherwise returns false and sets an error code which can be obtained by accessing the value of the QSerialPort::error property. + + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. */ bool QSerialPort::setStopBits(StopBits stopBits) { @@ -732,6 +764,13 @@ QSerialPort::StopBits QSerialPort::stopBits() const If the setting is successful, returns true; otherwise returns false and sets an error code which can be obtained by accessing the value of the QSerialPort::error property. + + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. */ bool QSerialPort::setFlowControl(FlowControl flow) { @@ -775,6 +814,13 @@ QSerialPort::FlowControl QSerialPort::flowControl() const If the setting is successful, returns true; otherwise returns false. If the flag is true then the DTR signal is set to high; otherwise low. + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. + \sa pinoutSignals() */ bool QSerialPort::setDataTerminalReady(bool set) @@ -818,6 +864,13 @@ bool QSerialPort::isDataTerminalReady() If the setting is successful, returns true; otherwise returns false. If the flag is true then the RTS signal is set to high; otherwise low. + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. + \sa pinoutSignals() */ bool QSerialPort::setRequestToSend(bool set) @@ -945,6 +998,13 @@ bool QSerialPort::atEnd() const If the setting is successful, returns true; otherwise returns false. The default policy set is IgnorePolicy. + + \note The serial port has to be open before trying to set this property; + otherwise returns false and sets the NotOpenError error code. This is a bit + unusual as opposed to the regular Qt property settings of a class. However, + this is a special use case since the property is set through the interaction + with the kernel and hardware. Hence, the two scenarios cannot be completely + compared to each other. */ bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) { -- cgit v1.2.1 From fbab2a56152c3ef31c7b26a8bf18420ed63fe65a Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Sat, 5 Oct 2013 10:01:12 +0100 Subject: Set the NotOpenError error code also for closing Change-Id: Iacf0235bd64bca8fbe4e2ce2c652cd89d3136b2f Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 602cf6a..a91a953 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -484,12 +484,16 @@ bool QSerialPort::open(OpenMode mode) /*! \reimp + \note The serial port has to be open before trying to close it; otherwise + sets the NotOpenError error code. + \sa QIODevice::close() */ void QSerialPort::close() { Q_D(QSerialPort); if (!isOpen()) { + setError(QSerialPort::NotOpenError); return; } -- cgit v1.2.1 From 2e237466d3f3e1f2d41be681364b76fe82b7886a Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Sat, 5 Oct 2013 19:14:34 +0100 Subject: Add an "UnknownSignal" value for the pinout signals This needs to be added to the API because there are situations where the serial line state is unknown. The two typical use cases are: 1) The syscall cannot retrieve the state for some reason. 2) The serial port is not open. This has been (only build!) tested on Linux (Arch) with Qt 4 and then 5. Change-Id: I471a68b2e335b54d9a94071f08b1b31a6fb0056a Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 1 + src/serialport/qserialport.h | 3 ++- src/serialport/qserialport_unix.cpp | 5 +++-- src/serialport/qserialport_win.cpp | 5 +++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index a91a953..1e22cf0 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -272,6 +272,7 @@ int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed) \value ClearToSendSignal CTS (Clear To Send). \value SecondaryTransmittedDataSignal STD (Secondary Transmitted Data). \value SecondaryReceivedDataSignal SRD (Secondary Received Data). + \value UnknownSignal Unknown line state. This value was introduced in QtSerialPort 5.2. \sa pinoutSignals(), QSerialPort::dataTerminalReady, QSerialPort::requestToSend diff --git a/src/serialport/qserialport.h b/src/serialport/qserialport.h index 81a39fb..e173445 100644 --- a/src/serialport/qserialport.h +++ b/src/serialport/qserialport.h @@ -140,7 +140,8 @@ public: RequestToSendSignal = 0x40, ClearToSendSignal = 0x80, SecondaryTransmittedDataSignal = 0x100, - SecondaryReceivedDataSignal = 0x200 + SecondaryReceivedDataSignal = 0x200, + UnknownSignal = -1 }; Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal) diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp index f72322f..ad91e1b 100644 --- a/src/serialport/qserialport_unix.cpp +++ b/src/serialport/qserialport_unix.cpp @@ -257,13 +257,14 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() Q_Q(QSerialPort); int arg = 0; - QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; if (::ioctl(descriptor, TIOCMGET, &arg) == -1) { q->setError(decodeSystemError()); - return ret; + return QSerialPort::UnknownSignal; } + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + #ifdef TIOCM_LE if (arg & TIOCM_LE) ret |= QSerialPort::DataSetReadySignal; diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 3d9e98a..834740d 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -320,13 +320,14 @@ QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() Q_Q(QSerialPort); DWORD modemStat = 0; - QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; if (!::GetCommModemStatus(descriptor, &modemStat)) { q->setError(decodeSystemError()); - return ret; + return QSerialPort::UnknownSignal; } + QSerialPort::PinoutSignals ret = QSerialPort::NoSignal; + if (modemStat & MS_CTS_ON) ret |= QSerialPort::ClearToSendSignal; if (modemStat & MS_DSR_ON) -- cgit v1.2.1 From 6e03505a1a2b6ce6e5dc1a5ee28c084ef4692380 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Sat, 5 Oct 2013 06:40:41 +0100 Subject: Return in certain methods if the device is not open This is necessary for a couple of methods because they require the port being open for being functional. Hence, if the port is not open, they now return properly on their own, and set the "NotOpenError" error code . This has been (only build!) tested on Linux (Arch) with Qt 4 and then 5. Change-Id: Ifc77bea581dd1832e188fa7562c5c1b15c0532e3 Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 70 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 1e22cf0..2242abf 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -819,12 +819,12 @@ QSerialPort::FlowControl QSerialPort::flowControl() const If the setting is successful, returns true; otherwise returns false. If the flag is true then the DTR signal is set to high; otherwise low. - \note The serial port has to be open before trying to set this property; - otherwise returns false and sets the NotOpenError error code. This is a bit - unusual as opposed to the regular Qt property settings of a class. However, - this is a special use case since the property is set through the interaction - with the kernel and hardware. Hence, the two scenarios cannot be completely - compared to each other. + \note The serial port has to be open before trying to set or get this + property; otherwise returns false and sets the NotOpenError error code. This + is a bit unusual as opposed to the regular Qt property settings of a class. + However, this is a special use case since the property is set through the + interaction with the kernel and hardware. Hence, the two scenarios cannot be + completely compared to each other. \sa pinoutSignals() */ @@ -869,12 +869,12 @@ bool QSerialPort::isDataTerminalReady() If the setting is successful, returns true; otherwise returns false. If the flag is true then the RTS signal is set to high; otherwise low. - \note The serial port has to be open before trying to set this property; - otherwise returns false and sets the NotOpenError error code. This is a bit - unusual as opposed to the regular Qt property settings of a class. However, - this is a special use case since the property is set through the interaction - with the kernel and hardware. Hence, the two scenarios cannot be completely - compared to each other. + \note The serial port has to be open before trying to set or get this + property; otherwise returns false and sets the NotOpenError error code. This + is a bit unusual as opposed to the regular Qt property settings of a class. + However, this is a special use case since the property is set through the + interaction with the kernel and hardware. Hence, the two scenarios cannot be + completely compared to each other. \sa pinoutSignals() */ @@ -923,12 +923,22 @@ bool QSerialPort::isRequestToSend() states are returned properly. This is necessary when the underlying operating systems cannot provide proper notifications about the changes. + \note The serial port has to be open before trying to get the pinout + signals; otherwise returns UnknownSignal and sets the NotOpenError error + code. + \sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(), setRequestToSend() */ QSerialPort::PinoutSignals QSerialPort::pinoutSignals() { Q_D(QSerialPort); + + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return QSerialPort::UnknownSignal; + } + return d->pinoutSignals(); } @@ -944,11 +954,20 @@ QSerialPort::PinoutSignals QSerialPort::pinoutSignals() returned to the event loop. In the absence of an event loop, call waitForBytesWritten() instead. + \note The serial port has to be open before trying to flush any buffered + data; otherwise returns false and sets the NotOpenError error code. + \sa write(), waitForBytesWritten() */ bool QSerialPort::flush() { Q_D(QSerialPort); + + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + return d->flush(); } @@ -957,10 +976,19 @@ bool QSerialPort::flush() given directions \a directions. Including clear an internal class buffers and the UART (driver) buffers. Also terminate pending read or write operations. If successful, returns true; otherwise returns false. + + \note The serial port has to be open before trying to clear any buffered + data; otherwise returns false and sets the NotOpenError error code. */ bool QSerialPort::clear(Directions directions) { Q_D(QSerialPort); + + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + if (directions & Input) d->readBuffer.clear(); if (directions & Output) @@ -1222,11 +1250,20 @@ bool QSerialPort::waitForBytesWritten(int msecs) If the duration is non zero then zero bits are transmitted within a certain period of time depending on the implementation. + \note The serial port has to be open before trying to send a break + duration; otherwise returns false and sets the NotOpenError error code. + \sa setBreakEnabled() */ bool QSerialPort::sendBreak(int duration) { Q_D(QSerialPort); + + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + return d->sendBreak(duration); } @@ -1236,11 +1273,20 @@ bool QSerialPort::sendBreak(int duration) If \a set is true then enables the break transmission; otherwise disables. + \note The serial port has to be open before trying to set break enabled; + otherwise returns false and sets the NotOpenError error code. + \sa sendBreak() */ bool QSerialPort::setBreakEnabled(bool set) { Q_D(QSerialPort); + + if (!isOpen()) { + setError(QSerialPort::NotOpenError); + return false; + } + return d->setBreakEnabled(set); } -- cgit v1.2.1 From da0c6b10881781fa52920a1c2dc4fce5b7be8a5e Mon Sep 17 00:00:00 2001 From: Alejandro Exojo Date: Wed, 2 Oct 2013 16:53:28 +0200 Subject: Don't link against QtGui in cenumerator Change-Id: Ibc730410bae66a8547733a66daa4d1dcb5808534 Reviewed-by: Laszlo Papp Reviewed-by: Denis Shienkov --- examples/serialport/cenumerator/cenumerator.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/serialport/cenumerator/cenumerator.pro b/examples/serialport/cenumerator/cenumerator.pro index 464e1d9..7f87034 100644 --- a/examples/serialport/cenumerator/cenumerator.pro +++ b/examples/serialport/cenumerator/cenumerator.pro @@ -1,3 +1,5 @@ +QT = core + greaterThan(QT_MAJOR_VERSION, 4) { QT += serialport } else { -- cgit v1.2.1 From 43f7c62509f71b16b263f4280ee55a350696ca00 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Tue, 8 Oct 2013 21:32:25 +0100 Subject: Add warnings to the methods requiring open serial port Change-Id: I441dcc6c94c75ceada684262b7ab68b5c3471aec Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/serialport/qserialport.cpp b/src/serialport/qserialport.cpp index 2242abf..04f2f9f 100644 --- a/src/serialport/qserialport.cpp +++ b/src/serialport/qserialport.cpp @@ -59,6 +59,8 @@ # define SERIALPORT_BUFFERSIZE 16384 #endif +#include + QT_BEGIN_NAMESPACE QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q) @@ -495,6 +497,7 @@ void QSerialPort::close() Q_D(QSerialPort); if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return; } @@ -566,6 +569,7 @@ bool QSerialPort::setBaudRate(qint32 baudRate, Directions directions) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -632,6 +636,7 @@ bool QSerialPort::setDataBits(DataBits dataBits) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -683,6 +688,7 @@ bool QSerialPort::setParity(Parity parity) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -733,6 +739,7 @@ bool QSerialPort::setStopBits(StopBits stopBits) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -783,6 +790,7 @@ bool QSerialPort::setFlowControl(FlowControl flow) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -834,6 +842,7 @@ bool QSerialPort::setDataTerminalReady(bool set) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -884,6 +893,7 @@ bool QSerialPort::setRequestToSend(bool set) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -936,6 +946,7 @@ QSerialPort::PinoutSignals QSerialPort::pinoutSignals() if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return QSerialPort::UnknownSignal; } @@ -965,6 +976,7 @@ bool QSerialPort::flush() if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -986,6 +998,7 @@ bool QSerialPort::clear(Directions directions) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1045,6 +1058,7 @@ bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1261,6 +1275,7 @@ bool QSerialPort::sendBreak(int duration) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } @@ -1284,6 +1299,7 @@ bool QSerialPort::setBreakEnabled(bool set) if (!isOpen()) { setError(QSerialPort::NotOpenError); + qWarning("%s: device not open", Q_FUNC_INFO); return false; } -- cgit v1.2.1 From 50ab4d4a8ff5f882b9699cbde26ad9d8824a4824 Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Sun, 6 Oct 2013 06:22:16 +0100 Subject: Eliminate the ifdef in the code for imported headers (qt4support) As I previously wrote on Gerrit, this idea of resembling the include hiearchy inside qt4support has two advantages: 1) The includes are well-separated for Qt 4 that are imported. 2) The code is less complex due to the non-existence of ifdefs for major Qt variants. The only disadvantage is that the build system got one additional line, but the benefits outweigh that. This has been (only build!) tested on Linux (Arch) with Qt 4 and then 5. Change-Id: Ic33632cd0e569693a65af094479dac0a02b1a7f7 Reviewed-by: Sergey Belyashov Reviewed-by: Denis Shienkov --- src/serialport/qserialport_p.h | 4 - src/serialport/qserialport_win.cpp | 4 - .../qt4support/include/QtCore/qwineventnotifier.h | 82 ++++ .../qt4support/include/private/qringbuffer_p.h | 451 +++++++++++++++++++++ src/serialport/qt4support/install-helper.pri | 1 + src/serialport/qt4support/qringbuffer_p.h | 451 --------------------- src/serialport/qt4support/qwineventnotifier_p.h | 94 ----- 7 files changed, 534 insertions(+), 553 deletions(-) create mode 100644 src/serialport/qt4support/include/QtCore/qwineventnotifier.h create mode 100644 src/serialport/qt4support/include/private/qringbuffer_p.h delete mode 100644 src/serialport/qt4support/qringbuffer_p.h delete mode 100644 src/serialport/qt4support/qwineventnotifier_p.h diff --git a/src/serialport/qserialport_p.h b/src/serialport/qserialport_p.h index cb6a748..4140493 100644 --- a/src/serialport/qserialport_p.h +++ b/src/serialport/qserialport_p.h @@ -46,11 +46,7 @@ #include "qserialport.h" -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include -#else -#include "qt4support/qringbuffer_p.h" -#endif QT_BEGIN_NAMESPACE diff --git a/src/serialport/qserialport_win.cpp b/src/serialport/qserialport_win.cpp index 834740d..91630fd 100644 --- a/src/serialport/qserialport_win.cpp +++ b/src/serialport/qserialport_win.cpp @@ -50,11 +50,7 @@ #include #endif -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include -#else -#include "qt4support/qwineventnotifier_p.h" -#endif #ifndef CTL_CODE # define CTL_CODE(DeviceType, Function, Method, Access) ( \ diff --git a/src/serialport/qt4support/include/QtCore/qwineventnotifier.h b/src/serialport/qt4support/include/QtCore/qwineventnotifier.h new file mode 100644 index 0000000..ed31e83 --- /dev/null +++ b/src/serialport/qt4support/include/QtCore/qwineventnotifier.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_H +#define QWINEVENTNOTIFIER_H + +#include "QtCore/qobject.h" + +#ifdef Q_OS_WIN +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class QWinEventNotifierPrivate; +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWinEventNotifier) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); +}; + +QT_END_NAMESPACE + +#endif // Q_OS_WIN + +#endif // QWINEVENTNOTIFIER_H diff --git a/src/serialport/qt4support/include/private/qringbuffer_p.h b/src/serialport/qt4support/include/private/qringbuffer_p.h new file mode 100644 index 0000000..ddd10e5 --- /dev/null +++ b/src/serialport/qt4support/include/private/qringbuffer_p.h @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRINGBUFFER_P_H +#define QRINGBUFFER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QRingBuffer +{ +public: + explicit inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { + buffers << QByteArray(); + clear(); + } + + inline int nextDataBlockSize() const { + return (tailBuffer == 0 ? tail : buffers.first().size()) - head; + } + + inline const char *readPointer() const { + return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); + } + + // access the bytes at a specified position + // the out-variable length will contain the amount of bytes readable + // from there, e.g. the amount still the same QByteArray + inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { + if (buffers.isEmpty()) { + length = 0; + return 0; + } + + if (pos >= bufferSize) { + length = 0; + return 0; + } + + // special case: it is in the first buffer + int nextDataBlockSizeValue = nextDataBlockSize(); + if (pos - head < nextDataBlockSizeValue) { + length = nextDataBlockSizeValue - pos; + return buffers.at(0).constData() + head + pos; + } + + // special case: we only had one buffer and tried to read over it + if (buffers.length() == 1) { + length = 0; + return 0; + } + + // skip the first + pos -= nextDataBlockSizeValue; + + // normal case: it is somewhere in the second to the-one-before-the-tailBuffer + for (int i = 1; i < tailBuffer; i++) { + if (pos >= buffers[i].size()) { + pos -= buffers[i].size(); + continue; + } + + length = buffers[i].length() - pos; + return buffers[i].constData() + pos; + } + + // it is in the tail buffer + length = tail - pos; + return buffers[tailBuffer].constData() + pos; + } + + inline void free(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + int nextBlockSize = nextDataBlockSize(); + if (bytes < nextBlockSize) { + head += bytes; + if (head == tail && tailBuffer == 0) + head = tail = 0; + break; + } + + bytes -= nextBlockSize; + if (buffers.count() == 1) { + if (buffers.at(0).size() != basicBlockSize) + buffers[0].resize(basicBlockSize); + head = tail = 0; + tailBuffer = 0; + break; + } + + buffers.removeAt(0); + --tailBuffer; + head = 0; + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + inline char *reserve(int bytes) { + // if this is a fresh empty QRingBuffer + if (bufferSize == 0) { + buffers[0].resize(qMax(basicBlockSize, bytes)); + bufferSize += bytes; + tail = bytes; + return buffers[tailBuffer].data(); + } + + bufferSize += bytes; + + // if there is already enough space, simply return. + if (tail + bytes <= buffers.at(tailBuffer).size()) { + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // if our buffer isn't half full yet, simply resize it. + if (tail < buffers.at(tailBuffer).size() / 2) { + buffers[tailBuffer].resize(tail + bytes); + char *writePtr = buffers[tailBuffer].data() + tail; + tail += bytes; + return writePtr; + } + + // shrink this buffer to its current size + buffers[tailBuffer].resize(tail); + + // create a new QByteArray with the right size + buffers << QByteArray(); + ++tailBuffer; + buffers[tailBuffer].resize(qMax(basicBlockSize, bytes)); + tail = bytes; + return buffers[tailBuffer].data(); + } + + inline void truncate(int pos) { + if (pos < size()) + chop(size() - pos); + } + + inline void chop(int bytes) { + bufferSize -= bytes; + if (bufferSize < 0) + bufferSize = 0; + + for (;;) { + // special case: head and tail are in the same buffer + if (tailBuffer == 0) { + tail -= bytes; + if (tail <= head) + tail = head = 0; + return; + } + + if (bytes <= tail) { + tail -= bytes; + return; + } + + bytes -= tail; + buffers.removeAt(tailBuffer); + + --tailBuffer; + tail = buffers.at(tailBuffer).size(); + } + + if (isEmpty()) + clear(); // try to minify/squeeze us + } + + inline bool isEmpty() const { + return tailBuffer == 0 && tail == 0; + } + + inline int getChar() { + if (isEmpty()) + return -1; + char c = *readPointer(); + free(1); + return int(uchar(c)); + } + + inline void putChar(char c) { + char *ptr = reserve(1); + *ptr = c; + } + + inline void ungetChar(char c) { + --head; + if (head < 0) { + buffers.prepend(QByteArray()); + buffers[0].resize(basicBlockSize); + head = basicBlockSize - 1; + ++tailBuffer; + } + buffers[0][head] = c; + ++bufferSize; + } + + inline int size() const { + return bufferSize; + } + + inline void clear() { + buffers.erase(buffers.begin() + 1, buffers.end()); + buffers[0].resize(0); + buffers[0].squeeze(); + + head = tail = 0; + tailBuffer = 0; + bufferSize = 0; + } + + inline int indexOf(char c) const { + int index = 0; + for (int i = 0; i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int indexOf(char c, int maxLength) const { + int index = 0; + int remain = qMin(size(), maxLength); + for (int i = 0; remain && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + if (remain < end - start) { + end = start + remain; + remain = 0; + } else { + remain -= end - start; + } + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + + inline int read(char *data, int maxLength) { + int bytesToRead = qMin(size(), maxLength); + int readSoFar = 0; + while (readSoFar < bytesToRead) { + const char *ptr = readPointer(); + int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize()); + if (data) + memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); + readSoFar += bytesToReadFromThisBlock; + free(bytesToReadFromThisBlock); + } + return readSoFar; + } + + inline QByteArray read(int maxLength) { + QByteArray tmp; + tmp.resize(qMin(maxLength, size())); + read(tmp.data(), tmp.size()); + return tmp; + } + + inline QByteArray readAll() { + return read(size()); + } + + // read an unspecified amount (will read the first buffer) + inline QByteArray read() { + if (bufferSize == 0) + return QByteArray(); + + // multiple buffers, just take the first one + if (head == 0 && tailBuffer != 0) { + QByteArray qba = buffers.takeFirst(); + --tailBuffer; + bufferSize -= qba.length(); + return qba; + } + + // one buffer with good value for head. Just take it. + if (head == 0 && tailBuffer == 0) { + QByteArray qba = buffers.takeFirst(); + qba.resize(tail); + buffers << QByteArray(); + bufferSize = 0; + tail = 0; + return qba; + } + + // Bad case: We have to memcpy. + // We can avoid by initializing the QRingBuffer with basicBlockSize of 0 + // and only using this read() function. + QByteArray qba(readPointer(), nextDataBlockSize()); + buffers.removeFirst(); + head = 0; + if (tailBuffer == 0) { + buffers << QByteArray(); + tail = 0; + } else { + --tailBuffer; + } + bufferSize -= qba.length(); + return qba; + } + + // append a new buffer to the end + inline void append(const QByteArray &qba) { + buffers[tailBuffer].resize(tail); + buffers << qba; + ++tailBuffer; + tail = qba.length(); + bufferSize += qba.length(); + } + + inline QByteArray peek(int maxLength) const { + int bytesToRead = qMin(size(), maxLength); + if (maxLength <= 0) + return QByteArray(); + QByteArray ret; + ret.resize(bytesToRead); + int readSoFar = 0; + for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + const int len = qMin(ret.size()-readSoFar, end-start); + memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len); + readSoFar += len; + } + Q_ASSERT(readSoFar == ret.size()); + return ret; + } + + inline int skip(int length) { + return read(0, length); + } + + inline int readLine(char *data, int maxLength) { + int index = indexOf('\n'); + if (index == -1) + return read(data, maxLength); + if (maxLength <= 0) + return -1; + + int readSoFar = 0; + while (readSoFar < index + 1 && readSoFar < maxLength - 1) { + int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize()); + bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar); + memcpy(data + readSoFar, readPointer(), bytesToRead); + readSoFar += bytesToRead; + free(bytesToRead); + } + + // Terminate it. + data[readSoFar] = '\0'; + return readSoFar; + } + + inline bool canReadLine() const { + return indexOf('\n') != -1; + } + +private: + QList buffers; + int head, tail; + int tailBuffer; // always buffers.size() - 1 + int basicBlockSize; + int bufferSize; +}; + +QT_END_NAMESPACE + +#endif // QRINGBUFFER_P_H diff --git a/src/serialport/qt4support/install-helper.pri b/src/serialport/qt4support/install-helper.pri index 9ec2e6b..6037caf 100644 --- a/src/serialport/qt4support/install-helper.pri +++ b/src/serialport/qt4support/install-helper.pri @@ -36,4 +36,5 @@ target.path = $$[QT_INSTALL_LIBS] INSTALLS += target INCLUDEPATH += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort +lessThan(QT_MAJOR_VERSION, 5): INCLUDEPATH += $$QTSERIALPORT_PROJECT_ROOT/src/serialport/qt4support/include DEFINES += QT_BUILD_SERIALPORT_LIB diff --git a/src/serialport/qt4support/qringbuffer_p.h b/src/serialport/qt4support/qringbuffer_p.h deleted file mode 100644 index ddd10e5..0000000 --- a/src/serialport/qt4support/qringbuffer_p.h +++ /dev/null @@ -1,451 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QRINGBUFFER_P_H -#define QRINGBUFFER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of a number of Qt sources files. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -class QRingBuffer -{ -public: - explicit inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { - buffers << QByteArray(); - clear(); - } - - inline int nextDataBlockSize() const { - return (tailBuffer == 0 ? tail : buffers.first().size()) - head; - } - - inline const char *readPointer() const { - return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); - } - - // access the bytes at a specified position - // the out-variable length will contain the amount of bytes readable - // from there, e.g. the amount still the same QByteArray - inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { - if (buffers.isEmpty()) { - length = 0; - return 0; - } - - if (pos >= bufferSize) { - length = 0; - return 0; - } - - // special case: it is in the first buffer - int nextDataBlockSizeValue = nextDataBlockSize(); - if (pos - head < nextDataBlockSizeValue) { - length = nextDataBlockSizeValue - pos; - return buffers.at(0).constData() + head + pos; - } - - // special case: we only had one buffer and tried to read over it - if (buffers.length() == 1) { - length = 0; - return 0; - } - - // skip the first - pos -= nextDataBlockSizeValue; - - // normal case: it is somewhere in the second to the-one-before-the-tailBuffer - for (int i = 1; i < tailBuffer; i++) { - if (pos >= buffers[i].size()) { - pos -= buffers[i].size(); - continue; - } - - length = buffers[i].length() - pos; - return buffers[i].constData() + pos; - } - - // it is in the tail buffer - length = tail - pos; - return buffers[tailBuffer].constData() + pos; - } - - inline void free(int bytes) { - bufferSize -= bytes; - if (bufferSize < 0) - bufferSize = 0; - - for (;;) { - int nextBlockSize = nextDataBlockSize(); - if (bytes < nextBlockSize) { - head += bytes; - if (head == tail && tailBuffer == 0) - head = tail = 0; - break; - } - - bytes -= nextBlockSize; - if (buffers.count() == 1) { - if (buffers.at(0).size() != basicBlockSize) - buffers[0].resize(basicBlockSize); - head = tail = 0; - tailBuffer = 0; - break; - } - - buffers.removeAt(0); - --tailBuffer; - head = 0; - } - - if (isEmpty()) - clear(); // try to minify/squeeze us - } - - inline char *reserve(int bytes) { - // if this is a fresh empty QRingBuffer - if (bufferSize == 0) { - buffers[0].resize(qMax(basicBlockSize, bytes)); - bufferSize += bytes; - tail = bytes; - return buffers[tailBuffer].data(); - } - - bufferSize += bytes; - - // if there is already enough space, simply return. - if (tail + bytes <= buffers.at(tailBuffer).size()) { - char *writePtr = buffers[tailBuffer].data() + tail; - tail += bytes; - return writePtr; - } - - // if our buffer isn't half full yet, simply resize it. - if (tail < buffers.at(tailBuffer).size() / 2) { - buffers[tailBuffer].resize(tail + bytes); - char *writePtr = buffers[tailBuffer].data() + tail; - tail += bytes; - return writePtr; - } - - // shrink this buffer to its current size - buffers[tailBuffer].resize(tail); - - // create a new QByteArray with the right size - buffers << QByteArray(); - ++tailBuffer; - buffers[tailBuffer].resize(qMax(basicBlockSize, bytes)); - tail = bytes; - return buffers[tailBuffer].data(); - } - - inline void truncate(int pos) { - if (pos < size()) - chop(size() - pos); - } - - inline void chop(int bytes) { - bufferSize -= bytes; - if (bufferSize < 0) - bufferSize = 0; - - for (;;) { - // special case: head and tail are in the same buffer - if (tailBuffer == 0) { - tail -= bytes; - if (tail <= head) - tail = head = 0; - return; - } - - if (bytes <= tail) { - tail -= bytes; - return; - } - - bytes -= tail; - buffers.removeAt(tailBuffer); - - --tailBuffer; - tail = buffers.at(tailBuffer).size(); - } - - if (isEmpty()) - clear(); // try to minify/squeeze us - } - - inline bool isEmpty() const { - return tailBuffer == 0 && tail == 0; - } - - inline int getChar() { - if (isEmpty()) - return -1; - char c = *readPointer(); - free(1); - return int(uchar(c)); - } - - inline void putChar(char c) { - char *ptr = reserve(1); - *ptr = c; - } - - inline void ungetChar(char c) { - --head; - if (head < 0) { - buffers.prepend(QByteArray()); - buffers[0].resize(basicBlockSize); - head = basicBlockSize - 1; - ++tailBuffer; - } - buffers[0][head] = c; - ++bufferSize; - } - - inline int size() const { - return bufferSize; - } - - inline void clear() { - buffers.erase(buffers.begin() + 1, buffers.end()); - buffers[0].resize(0); - buffers[0].squeeze(); - - head = tail = 0; - tailBuffer = 0; - bufferSize = 0; - } - - inline int indexOf(char c) const { - int index = 0; - for (int i = 0; i < buffers.size(); ++i) { - int start = 0; - int end = buffers.at(i).size(); - - if (i == 0) - start = head; - if (i == tailBuffer) - end = tail; - const char *ptr = buffers.at(i).data() + start; - for (int j = start; j < end; ++j) { - if (*ptr++ == c) - return index; - ++index; - } - } - return -1; - } - - inline int indexOf(char c, int maxLength) const { - int index = 0; - int remain = qMin(size(), maxLength); - for (int i = 0; remain && i < buffers.size(); ++i) { - int start = 0; - int end = buffers.at(i).size(); - - if (i == 0) - start = head; - if (i == tailBuffer) - end = tail; - if (remain < end - start) { - end = start + remain; - remain = 0; - } else { - remain -= end - start; - } - const char *ptr = buffers.at(i).data() + start; - for (int j = start; j < end; ++j) { - if (*ptr++ == c) - return index; - ++index; - } - } - return -1; - } - - inline int read(char *data, int maxLength) { - int bytesToRead = qMin(size(), maxLength); - int readSoFar = 0; - while (readSoFar < bytesToRead) { - const char *ptr = readPointer(); - int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize()); - if (data) - memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); - readSoFar += bytesToReadFromThisBlock; - free(bytesToReadFromThisBlock); - } - return readSoFar; - } - - inline QByteArray read(int maxLength) { - QByteArray tmp; - tmp.resize(qMin(maxLength, size())); - read(tmp.data(), tmp.size()); - return tmp; - } - - inline QByteArray readAll() { - return read(size()); - } - - // read an unspecified amount (will read the first buffer) - inline QByteArray read() { - if (bufferSize == 0) - return QByteArray(); - - // multiple buffers, just take the first one - if (head == 0 && tailBuffer != 0) { - QByteArray qba = buffers.takeFirst(); - --tailBuffer; - bufferSize -= qba.length(); - return qba; - } - - // one buffer with good value for head. Just take it. - if (head == 0 && tailBuffer == 0) { - QByteArray qba = buffers.takeFirst(); - qba.resize(tail); - buffers << QByteArray(); - bufferSize = 0; - tail = 0; - return qba; - } - - // Bad case: We have to memcpy. - // We can avoid by initializing the QRingBuffer with basicBlockSize of 0 - // and only using this read() function. - QByteArray qba(readPointer(), nextDataBlockSize()); - buffers.removeFirst(); - head = 0; - if (tailBuffer == 0) { - buffers << QByteArray(); - tail = 0; - } else { - --tailBuffer; - } - bufferSize -= qba.length(); - return qba; - } - - // append a new buffer to the end - inline void append(const QByteArray &qba) { - buffers[tailBuffer].resize(tail); - buffers << qba; - ++tailBuffer; - tail = qba.length(); - bufferSize += qba.length(); - } - - inline QByteArray peek(int maxLength) const { - int bytesToRead = qMin(size(), maxLength); - if (maxLength <= 0) - return QByteArray(); - QByteArray ret; - ret.resize(bytesToRead); - int readSoFar = 0; - for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) { - int start = 0; - int end = buffers.at(i).size(); - if (i == 0) - start = head; - if (i == tailBuffer) - end = tail; - const int len = qMin(ret.size()-readSoFar, end-start); - memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len); - readSoFar += len; - } - Q_ASSERT(readSoFar == ret.size()); - return ret; - } - - inline int skip(int length) { - return read(0, length); - } - - inline int readLine(char *data, int maxLength) { - int index = indexOf('\n'); - if (index == -1) - return read(data, maxLength); - if (maxLength <= 0) - return -1; - - int readSoFar = 0; - while (readSoFar < index + 1 && readSoFar < maxLength - 1) { - int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize()); - bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar); - memcpy(data + readSoFar, readPointer(), bytesToRead); - readSoFar += bytesToRead; - free(bytesToRead); - } - - // Terminate it. - data[readSoFar] = '\0'; - return readSoFar; - } - - inline bool canReadLine() const { - return indexOf('\n') != -1; - } - -private: - QList buffers; - int head, tail; - int tailBuffer; // always buffers.size() - 1 - int basicBlockSize; - int bufferSize; -}; - -QT_END_NAMESPACE - -#endif // QRINGBUFFER_P_H diff --git a/src/serialport/qt4support/qwineventnotifier_p.h b/src/serialport/qt4support/qwineventnotifier_p.h deleted file mode 100644 index bd1203e..0000000 --- a/src/serialport/qt4support/qwineventnotifier_p.h +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QWINEVENTNOTIFIER_P_H -#define QWINEVENTNOTIFIER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qobject.h" -#include "QtCore/qt_windows.h" - -QT_BEGIN_NAMESPACE - -class Q_CORE_EXPORT QWinEventNotifier : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QObject) - -public: - explicit QWinEventNotifier(QObject *parent = 0); - explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); - ~QWinEventNotifier(); - - void setHandle(HANDLE hEvent); - HANDLE handle() const; - - bool isEnabled() const; - -public Q_SLOTS: - void setEnabled(bool enable); - -Q_SIGNALS: - void activated(HANDLE hEvent); - -protected: - bool event(QEvent * e); - -private: - Q_DISABLE_COPY(QWinEventNotifier) - - HANDLE handleToEvent; - bool enabled; -}; - -QT_END_NAMESPACE - -#endif // QWINEVENTNOTIFIER_P_H -- cgit v1.2.1