diff options
Diffstat (limited to 'examples/serialport/doc/blockingreceiver.qdoc')
-rw-r--r-- | examples/serialport/doc/blockingreceiver.qdoc | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/examples/serialport/doc/blockingreceiver.qdoc b/examples/serialport/doc/blockingreceiver.qdoc new file mode 100644 index 0000000..555b2db --- /dev/null +++ b/examples/serialport/doc/blockingreceiver.qdoc @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Denis Shienkov <denis.shienkov@gmail.com> +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example blockingreceiver + \title Blocking Receiver Example + \ingroup qtserialport-examples + \brief Shows how to use the synchronous API of QSerialPort in a non-GUI thread. + + \e{Blocking Receiver} shows how to create an application for a serial interface + using QSerialPort's synchronous API in a non-GUI thread. + + \image blockingreceiver-example.png + + QSerialPort supports two general programming approaches: + + \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 synchronous (blocking) approach.} In non-GUI and multithreaded + applications, the \c waitFor...() functions can be called (i.e. + QSerialPort::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. + + 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 unmanageable complexity to your application. + + This application is a Receiver, that demonstrate the work paired with Sender + application \l{Blocking Sender Example}. + + The Receiver application receives the request via serial port from + the Sender application and send a response to it. + + We will start with the ReceiverThread class, which handles the serial + programming code. + + \snippet blockingreceiver/receiverthread.h 0 + + ReceiverThread is a QThread subclass that provides an API for receive requests + from Sender, and it has signals for delivering responses and reporting + errors. + + You should call startReceiver() to startup Receiver application. This method + transfers to the ReceiverThread desired parameters for configure and startup + the serial interface. When ReceiverThread received from Sender any request then + emitted the request() signal. If any error occurs, the error() or timeout() + signals is emitted. + + It's important to notice that startReceiver() is called from the main, GUI + thread, but the response data and other parameters will be accessed from + ReceiverThread's thread. ReceiverThread's data members are read and written + from different threads concurrently, so it is advisable to use QMutex to + synchronize access. + + \snippet blockingreceiver/receiverthread.cpp 2 + + The startReceiver() function stores the serial port name, timeout and response + data, and QMutexLocker locks the mutex to protect these data. We then + start the thread, unless it is already running. QWaitCondition::wakeOne() + will be discussed later. + + \snippet blockingreceiver/receiverthread.cpp 4 + \snippet blockingreceiver/receiverthread.cpp 5 + + In the run() function, start by acquiring the mutex lock, fetch the + serial port name, timeout and response data from the member data, and then + release the lock again. Under no circumstance should the method \c startReceiver() + 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 startup, call and timeout or response data of another. ReceiverThread + can only handle one startup at a time. + + The QSerialPort object we construct on stack into run() function before loop + enter: + + \snippet blockingreceiver/receiverthread.cpp 6 + + This allows us once to create an object, while running loop, and also means + that all the methods of the object will be executed in the context of the + run() thread. + + In the loop, check whether the name of the serial port for the current + startup has changed or not. If it has, re-open and reconfigure the serial port. + + \snippet blockingreceiver/receiverthread.cpp 7 + + The loop will continue waiting for request data: + + \snippet blockingreceiver/receiverthread.cpp 8 + + \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. + + The timeout() signal is emitted if an error occurs when reading data. + + \snippet blockingreceiver/receiverthread.cpp 9 + + After a successful read, try to send a response and wait for completion of the + transfer: + + \snippet blockingreceiver/receiverthread.cpp 10 + + \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 Qt event-loop. + + The timeout() signal is emitted if an error occurs when writing data. + + \snippet blockingreceiver/receiverthread.cpp 11 + + After a successful writing is emitted, request() signal containing the + data received from the Sender application: + + \snippet blockingreceiver/receiverthread.cpp 12 + + Next, the thread switches to reading the current parameters for the serial + interface, because they can already have been updated, and run the loop + from the beginning. + + \snippet blockingreceiver/receiverthread.cpp 13 + + \sa {Terminal Example}, {Blocking Sender Example} + + \include examples-run.qdocinc +*/ |