mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-22 05:30:44 +00:00
164 lines
6.8 KiB
Plaintext
164 lines
6.8 KiB
Plaintext
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2011 - 2012 Denis Shienkov <denis.shienkov@gmail.com>
|
|
** Contact: http://www.qt-project.org/legal
|
|
**
|
|
** 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 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 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: http://www.gnu.org/copyleft/fdl.html.
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
/*!
|
|
\example blockingslave
|
|
\title Blocking Slave Example
|
|
\ingroup qtserialport-examples
|
|
|
|
The Blocking Slave example shows how to create a application for a
|
|
serial interface using QSerialPort's synchronous API in a non-GUI thread.
|
|
|
|
\image blockingslave-example.png Screenshot of the Blocking Slave example
|
|
|
|
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 Slave, that demonstrate the work paired with Master
|
|
application \l{Blocking Master Example}.
|
|
|
|
The Slave application is receives the request via serial port from
|
|
the Master application and send a response to it.
|
|
|
|
We will start with the SlaveThread class, which handles the serial
|
|
programming code.
|
|
|
|
\snippet blockingslave/slavethread.h 0
|
|
|
|
SlaveThread is a QThread subclass that provides an API for receive requests
|
|
from Master, and it has signals for delivering responses and reporting
|
|
errors.
|
|
|
|
You should be call startSlave() to startup Slave application. This method
|
|
transfers to the SlaveThread desired parameters for configure and startup
|
|
the serial interface. When SlaveThread received from Master any request then
|
|
emitted the request() signal. If any error occurs, the error() or timeout()
|
|
signals is emitted.
|
|
|
|
It's important to notice that startSlave() is called from the main, GUI
|
|
thread, but the response data and other parameters will be accessed from
|
|
SlaveThread's thread. SlaveThread's data members are read and written
|
|
from different threads concurrently, so it is advisable to use QMutex to
|
|
synchronize access.
|
|
|
|
\snippet blockingslave/slavethread.cpp 2
|
|
|
|
The startSlave() 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 blockingslave/slavethread.cpp 4
|
|
\snippet blockingslave/slavethread.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 startSlave()
|
|
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. SlaveThread
|
|
can only handle one startup at a time.
|
|
|
|
The QSerialPort object we construct on stack into run() function before loop
|
|
enter:
|
|
|
|
\snippet blockingslave/slavethread.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 blockingslave/slavethread.cpp 7
|
|
|
|
The loop will continue waiting for request data:
|
|
|
|
\snippet blockingslave/slavethread.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 error occurs when reading data.
|
|
|
|
\snippet blockingslave/slavethread.cpp 9
|
|
|
|
After a successful read, try to send a response and wait for completion of the
|
|
transfer:
|
|
|
|
\snippet blockingslave/slavethread.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 blockingslave/slavethread.cpp 11
|
|
|
|
After a successful writing is emitted, request() signal containing the
|
|
data received from the Master application:
|
|
|
|
\snippet blockingslave/slavethread.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 blockingslave/slavethread.cpp 13
|
|
|
|
\sa {Terminal Example}, {Blocking Master Example}
|
|
*/
|