| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 - 2012 Denis Shienkov <denis.shienkov@gmail.com> |
| ** Copyright (C) 2012 - 2013 Laszlo Papp <lpapp@kde.org> |
| ** 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 blockingmaster |
| \title Blocking Master Example |
| \ingroup qtserialport-examples |
| \brief Shows how to use the synchronous API of QSerialPort in a worker thread. |
| |
| \e{Blocking Master} shows how to create an application for a serial |
| interface using the synchronous API of QSerialPort in a worker thread. |
| |
| \image blockingmaster-example.png |
| |
| QSerialPort supports two programming alternatives: |
| |
| \list |
| |
| \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) 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 alternative is demonstrated. The |
| \l{terminal}{Terminal} example illustrates the asynchronous alternative. |
| |
| 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}. |
| |
| The master application initiates the transfer request via the serial port to |
| the slave application and waits for response. |
| |
| \snippet blockingmaster/masterthread.h 0 |
| |
| 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. |
| |
| 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() 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, 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 \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 is constructed on stack in the run() method before |
| entering the loop: |
| |
| \snippet blockingmaster/masterthread.cpp 6 |
| |
| 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. |
| |
| 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 |
| |
| The loop will continue to request data, write to the serial port and wait |
| until all data is transferred. |
| |
| \snippet blockingmaster/masterthread.cpp 8 |
| |
| \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 a timeout error occurs when transferring |
| data. |
| |
| \snippet blockingmaster/masterthread.cpp 9 |
| |
| There is a waiting period for response after a successful request, and then |
| it is read again. |
| |
| \snippet blockingmaster/masterthread.cpp 10 |
| |
| \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 a timeout error occurs when receiving data. |
| |
| \snippet blockingmaster/masterthread.cpp 11 |
| |
| When a transaction has been completed successfully, the response() signal contains |
| the data received from the slave application: |
| |
| \snippet blockingmaster/masterthread.cpp 12 |
| |
| 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 |
| |
| \sa {Terminal Example}, {Blocking Slave Example} |
| |
| \include examples-run.qdocinc |
| */ |