Commit c2abde10 authored by Bill Bonney's avatar Bill Bonney

adds missing files

parent 04040e40
INCLUDEPATH += $$PWD
unix {
CONFIG += link_pkgconfig
packagesExist(libudev) {
DEFINES += HAVE_LIBUDEV
PKGCONFIG += libudev
}
}
PUBLIC_HEADERS += \
$$PWD/qserialportglobal.h \
$$PWD/qserialport.h \
$$PWD/qserialportinfo.h
PRIVATE_HEADERS += \
$$PWD/qserialport_p.h \
$$PWD/qserialportinfo_p.h
SOURCES += \
$$PWD/qserialport.cpp \
$$PWD/qserialportinfo.cpp
win32 {
PRIVATE_HEADERS += \
$$PWD/qserialport_win_p.h
SOURCES += \
$$PWD/qserialport_win.cpp \
$$PWD/qserialportinfo_win.cpp
LIBS += -lsetupapi -ladvapi32
}
unix:!symbian {
PRIVATE_HEADERS += \
$$PWD/qttylocker_unix_p.h \
$$PWD/qserialport_unix_p.h
SOURCES += \
$$PWD/qttylocker_unix.cpp \
$$PWD/qserialport_unix.cpp \
$$PWD/qserialportinfo_unix.cpp
macx {
SOURCES += $$PWD/qserialportinfo_mac.cpp
LIBS += -framework IOKit -framework CoreFoundation
} else {
linux*:contains( DEFINES, HAVE_LIBUDEV ) {
LIBS += -ludev
}
}
}
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtSerialPort
description = Qt Serial Port Reference Documentation
url = http://qt-project.org/doc/qt-$QT_VER/qtserialport
version = $QT_VERSION
qhp.projects = QtSerialPort
qhp.QtSerialPort.file = qtserialport.qhp
qhp.QtSerialPort.namespace = org.qt-project.qtserialport.$QT_VERSION_TAG
qhp.QtSerialPort.virtualFolder = qtserialport
qhp.QtSerialPort.indexTitle = Qt Serial Port
qhp.QtSerialPort.indexRoot =
qhp.QtSerialPort.filterAttributes = qtserialport $QT_VERSION qtrefdoc
qhp.QtSerialPort.customFilters.Qt.name = QtSerialPort $QT_VERSION
qhp.QtSerialPort.customFilters.Qt.filterAttributes = qtserialport $QT_VERSION
qhp.QtSerialPort.subprojects = classes examples
qhp.QtSerialPort.subprojects.classes.title = C++ Classes
qhp.QtSerialPort.subprojects.classes.indexTitle = Qt Serial Port C++ Classes
qhp.QtSerialPort.subprojects.classes.selectors = class fake:headerfile
qhp.QtSerialPort.subprojects.classes.sortPages = true
qhp.QtSerialPort.subprojects.examples.title = Examples
qhp.QtSerialPort.subprojects.examples.indexTitle = Qt Serial Port Examples
qhp.QtSerialPort.subprojects.examples.selectors = fake:example
qhp.QtSerialPort.subprojects.examples.sortPages = true
headerdirs += ..
sourcedirs += ..
exampledirs += ../../../examples/serialport
imagedirs += images
depends += qtcore qtdoc
/****************************************************************************
**
** 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$
**
****************************************************************************/
/*!
\page qtserialport-index.html
\title Qt Serial Port
\brief Provides API to make the serial programming simple and portable.
Qt Serial Port provides the basic functionality, which includes
configuring, I/O operations, get and set control signals of the
RS-232 pinouts.
The following are not supported by this module:
\list
\li Terminal features such as echo, control CR/LF, and so on.
\li Text mode.
\li Configuring timeouts and delays while reading.
\li Tracking and notification when the state of RS-232 pinout signals change.
\endlist
To use these classes in your application, use the following include
statement:
\code
#include <QtSerialPort/QtSerialPort>
\endcode
To link against the module, add this line to your \l qmake \c
.pro file:
\code
QT += serialport
\endcode
\section1 Related information
\list
\li \l{Qt Serial Port C++ Classes}{C++ Classes}
\li \l{Qt Serial Port Examples}{Examples}
\endlist
*/
/****************************************************************************
**
** 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$
**
****************************************************************************/
/*!
\module QtSerialPort
\title Qt Serial Port C++ Classes
\brief List of C++ classes that enable access to a serial port.
To use these classes in your application, use the following include
statement:
\code
#include <QtSerialPort/QtSerialPort>
\endcode
To link against the module, add this line to your \l qmake \c
.pro file:
\code
QT += serialport
\endcode
*/
a:link, a:visited {
color: #00732F;
text-decoration: none;
font-weight: bold;
}
body {
font: normal 400 14px/1.2 Arial;
margin-top: 85px;
}
h1 {
margin: 0;
}
h2 {
font: 500 20px/1.2 Arial;
}
h3.fn, span.fn {
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border-width: 1px;
border-style: solid;
border-color: #E6E6E6;
word-spacing: 3px;
padding: 3px 5px;
}
table, pre {
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border: 1px solid #E6E6E6;
border-collapse: separate;
font-size: 12px;
line-height: 1.2;
margin-bottom: 25px;
margin-left: 15px;
}
table td {
padding: 3px 15px 3px 20px;
}
table tr.even {
background-color: white;
color: #66666E;
}
table tr.odd {
background-color: #F6F6F6;
color: #66666E;
}
li {
margin-bottom: 10px;
padding-left: 12px;
}
.cpp {
display: block;
margin: 10;
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
padding: 20px 0 20px 0;
}
.footer {
margin-top: 50px;
}
.memItemLeft {
padding-right: 3px;
}
.memItemRight {
padding: 3px 15px 3px 0;
}
.qml {
display: block;
margin: 10;
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
padding: 20px 0 20px 0;
}
.qmldefault {
padding-left: 5px;
float: right;
color: red;
}
.qmlreadonly {
padding-left: 5px;
float: right;
color: #254117;
}
.rightAlign {
padding: 3px 5px 3px 10px;
text-align: right;
}
.title {
background-color: white;
color: #44A51C;
font-family: Verdana;
font-size: 35px;
font-weight: normal;
left: 0;
padding-bottom: 5px;
padding-left: 16px;
padding-top: 20px;
position: absolute;
right: 0;
top: 0;
}
.toc {
float: right;
-moz-border-radius: 7px 7px 7px 7px;
-webkit-border-radius: 7px 7px 7px 7px;
border-radius: 7px 7px 7px 7px;
background-color: #F6F6F6;
border: 1px solid #DDD;
margin: 0 20px 10px 10px;
padding: 20px 15px 20px 20px;
height: auto;
width: 200px;
}
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialport.h"
#include "qserialportinfo.h"
#ifdef Q_OS_WIN
#include "qserialport_win_p.h"
#elif defined (Q_OS_SYMBIAN)
#include "qserialport_symbian_p.h"
#elif defined (Q_OS_UNIX)
#include "qserialport_unix_p.h"
#else
#error Unsupported OS
#endif
#ifndef SERIALPORT_BUFFERSIZE
# define SERIALPORT_BUFFERSIZE 16384
#endif
QT_BEGIN_NAMESPACE
QSerialPortPrivateData::QSerialPortPrivateData(QSerialPort *q)
: readBufferMaxSize(0)
, readBuffer(SERIALPORT_BUFFERSIZE)
, writeBuffer(SERIALPORT_BUFFERSIZE)
, error(QSerialPort::NoError)
, inputBaudRate(0)
, outputBaudRate(0)
, dataBits(QSerialPort::UnknownDataBits)
, parity(QSerialPort::UnknownParity)
, stopBits(QSerialPort::UnknownStopBits)
, flow(QSerialPort::UnknownFlowControl)
, policy(QSerialPort::IgnorePolicy)
, settingsRestoredOnClose(true)
, q_ptr(q)
{
}
int QSerialPortPrivateData::timeoutValue(int msecs, int elapsed)
{
if (msecs == -1)
return msecs;
msecs -= elapsed;
return qMax(msecs, 0);
}
/*!
\class QSerialPort
\brief Provides functions to access serial ports.
\reentrant
\ingroup serialport-main
\inmodule QtSerialPort
\since 5.1
You can get information about the available serial ports using the
QSerialPortInfo helper class, which allows an enumeration of all the serial
ports in the system. This is useful to obtain the correct name of the
serial port you want to use. You can pass an object
of the helper class as an argument to the setPort() or setPortName()
methods to assign the desired serial device.
After setting the port, you can open it in read-only (r/o), write-only
(w/o), or read-write (r/w) mode using the open() method.
\note The serial port is always opened with exclusive access
(that is, no other process or thread can access an already opened serial port).
Having successfully opened, QSerialPort tries to determine the current
configuration of the port and initializes itself. You can reconfigure the
port to the desired setting using the setBaudRate(), setDataBits(),
setParity(), setStopBits(), and setFlowControl() methods.
The status of the control pinout signals is determined with the
isDataTerminalReady(), isRequestToSend, and pinoutSignals() methods. To
change the control line status, use the setDataTerminalReady(), and
setRequestToSend() methods.
Once you know that the ports are ready to read or write, you can
use the read() or write() methods. Alternatively the
readLine() and readAll() convenience methods can also be invoked.
If not all the data is read at once, the remaining data will
be available for later as new incoming data is appended to the
QSerialPort's internal read buffer. You can limit the size of the read
buffer using setReadBufferSize().
Use the close() method to close the port and cancel the I/O operations.
See the following example:
\code
int numRead = 0, numReadTotal = 0;
char buffer[50];
forever {
numRead = serial.read(buffer, 50);
// Do whatever with the array
numReadTotal += numRead;
if (numRead == 0 && !serial.waitForReadyRead())
break;
}
\endcode
If \l{QIODevice::}{waitForReadyRead()} returns false, the
connection has been closed or an error has occurred.
Programming with a blocking serial port is radically different from
programming with a non-blocking serial port. A blocking serial port
does not require an event loop and typically leads to simpler code.
However, in a GUI application, blocking serial port should only be
used in non-GUI threads, to avoid freezing the user interface.
For more details about these approaches, refer to the
\l {Examples}{example} applications.
The QSerialPort class can also be used with QTextStream and QDataStream's
stream operators (operator<<() and operator>>()). There is one issue to be
aware of, though: make sure that enough data is available before attempting
to read by using the operator>>() overloaded operator.
\sa QSerialPortInfo
*/
/*!
\enum QSerialPort::Direction
This enum describes the possible directions of the data transmission.
\note This enumeration is used for setting the baud rate of the device
separately for each direction on some operating systems (for example,
POSIX-like).
\value Input Input direction.
\value Output Output direction.
\value AllDirections Simultaneously in two directions.
*/
/*!
\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.
\value Baud1200 1200 baud.
\value Baud2400 2400 baud.
\value Baud4800 4800 baud.
\value Baud9600 9600 baud.
\value Baud19200 19200 baud.
\value Baud38400 38400 baud.
\value Baud57600 57600 baud.
\value Baud115200 115200 baud.
\value UnknownBaud Unknown baud.
\sa QSerialPort::baudRate
*/
/*!
\enum QSerialPort::DataBits
This enum describes the number of data bits used.
\value Data5 Five bits.
\value Data6 Six bits.
\value Data7 Seven bits
\value Data8 Eight bits.
\value UnknownDataBits Unknown number of bits.
\sa QSerialPort::dataBits
*/
/*!
\enum QSerialPort::Parity
This enum describes the parity scheme used.
\value NoParity No parity.
\value EvenParity Even parity.
\value OddParity Odd parity.
\value SpaceParity Space parity.
\value MarkParity Mark parity.
\value UnknownParity Unknown parity.
\sa QSerialPort::parity
*/
/*!
\enum QSerialPort::StopBits
This enum describes the number of stop bits used.
\value OneStop 1 stop bit.
\value OneAndHalfStop 1.5 stop bits.
\value TwoStop 2 stop bits.
\value UnknownStopBits Unknown number of stop bit.
\sa QSerialPort::stopBits
*/
/*!
\enum QSerialPort::FlowControl
This enum describes the flow control used.
\value NoFlowControl No flow control.
\value HardwareControl Hardware flow control (RTS/CTS).
\value SoftwareControl Software flow control (XON/XOFF).
\value UnknownFlowControl Unknown flow control.
\sa QSerialPort::flowControl
*/
/*!
\enum QSerialPort::PinoutSignal
This enum describes the possible RS-232 pinout signals.
\value NoSignal No line active
\value TransmittedDataSignal TxD (Transmitted Data).
\value ReceivedDataSignal RxD (Received Data).
\value DataTerminalReadySignal DTR (Data Terminal Ready).
\value DataCarrierDetectSignal DCD (Data Carrier Detect).
\value DataSetReadySignal DSR (Data Set Ready).
\value RingIndicatorSignal RNG (Ring Indicator).
\value RequestToSendSignal RTS (Request To Send).
\value ClearToSendSignal CTS (Clear To Send).
\value SecondaryTransmittedDataSignal STD (Secondary Transmitted Data).
\value SecondaryReceivedDataSignal SRD (Secondary Received Data).
\sa pinoutSignals(), QSerialPort::dataTerminalReady,
QSerialPort::requestToSend
*/
/*!
\enum QSerialPort::DataErrorPolicy
This enum describes the policies for the received symbols
while parity errors were detected.
\value SkipPolicy Skips the bad character.
\value PassZeroPolicy Replaces bad character to zero.
\value IgnorePolicy Ignores the error for a bad character.
\value StopReceivingPolicy Stops data reception on error.
\value UnknownPolicy Unknown policy.
\sa QSerialPort::dataErrorPolicy
*/
/*!
\enum QSerialPort::SerialPortError
This enum describes the errors that may be contained by the
QSerialPort::error property.
\value NoError No error occurred.
\value DeviceNotFoundError An error occurred while attempting to
open an non-existing device.
\value PermissionError An error occurred while attempting to
open an already opened device by another process or a user not
having enough permission and credentials to open.
\value OpenError An error occurred while attempting to
open an already opened device in this object.
\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
the input line.
\value WriteError An I/O error occurred while writing the data.
\value ReadError An I/O error occurred while reading the data.
\value ResourceError An I/O error occurred when a resource becomes unavailable,
e.g. when the device is unexpectedly removed from the system.
\value UnsupportedOperationError The requested device operation is
not supported or prohibited by the running operating system.
\value UnknownError An unidentified error occurred.
\sa QSerialPort::error
*/
/*!
Constructs a new serial port object with the given \a parent.
*/
QSerialPort::QSerialPort(QObject *parent)
: QIODevice(parent)
, d_ptr(new QSerialPortPrivate(this))
{}
/*!
Constructs a new serial port object with the given \a parent
to represent the serial port with the specified \a name.
The name should have a specific format; see the setPort() method.
*/
QSerialPort::QSerialPort(const QString &name, QObject *parent)
: QIODevice(parent)
, d_ptr(new QSerialPortPrivate(this))
{
setPortName(name);
}
/*!
Constructs a new serial port object with the given \a parent
to represent the serial port with the specified helper class
\a serialPortInfo.
*/
QSerialPort::QSerialPort(const QSerialPortInfo &serialPortInfo, QObject *parent)
: QIODevice(parent)
, d_ptr(new QSerialPortPrivate(this))
{
setPort(serialPortInfo);
}
/*!
Closes the serial port, if necessary, and then destroys object.
*/
QSerialPort::~QSerialPort()
{
/**/
close();
delete d_ptr;
}
/*!
Sets the \a name of the serial port.
The name of the serial port can be passed on as either a short name or
the long system location if necessary.
\sa portName(), QSerialPortInfo
*/
void QSerialPort::setPortName(const QString &name)
{
Q_D(QSerialPort);
d->systemLocation = QSerialPortPrivate::portNameToSystemLocation(name);
}
/*!
Sets the port stored in the serial port info instance \a serialPortInfo.
\sa portName(), QSerialPortInfo
*/
void QSerialPort::setPort(const QSerialPortInfo &serialPortInfo)
{
Q_D(QSerialPort);
d->systemLocation = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.systemLocation());
}
/*!
Returns the name set by setPort() or to the QSerialPort constructors.
This name is short, i.e. it extract and convert out from the internal
variable system location of the device. Conversion algorithm is
platform specific:
\table
\header
\li Platform
\li Brief Description
\row
\li Windows
\li Removes the prefix "\\\\.\\" from the system location
and returns the remainder of the string.
\row
\li Windows CE
\li Removes the postfix ":" from the system location
and returns the remainder of the string.
\row
\li Symbian
\li Returns the system location as it is,
as it is equivalent to the port name.
\row
\li GNU/Linux
\li Removes the prefix "/dev/" from the system location
and returns the remainder of the string.
\row
\li Mac OSX
\li Removes the prefix "/dev/cu." and "/dev/tty." from the
system location and returns the remainder of the string.
\row
\li Other *nix
\li The same as for GNU/Linux.
\endtable
\sa setPort(), QSerialPortInfo::portName()
*/
QString QSerialPort::portName() const
{
Q_D(const QSerialPort);
return QSerialPortPrivate::portNameFromSystemLocation(d->systemLocation);
}
/*!
\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
obtained by calling the error() method.
\warning The \a mode has to be QIODevice::ReadOnly, QIODevice::WriteOnly,
or QIODevice::ReadWrite. Other modes are unsupported.
\sa QIODevice::OpenMode, setPort()
*/
bool QSerialPort::open(OpenMode mode)
{
Q_D(QSerialPort);
if (isOpen()) {
setError(QSerialPort::OpenError);
return false;
}
// Define while not supported modes.
static const OpenMode unsupportedModes = Append | Truncate | Text | Unbuffered;
if ((mode & unsupportedModes) || mode == NotOpen) {
setError(QSerialPort::UnsupportedOperationError);
return false;
}
clearError();
if (d->open(mode)) {
QIODevice::open(mode);
d->dataTerminalReady = isDataTerminalReady();
d->requestToSend = isRequestToSend();
return true;
}
return false;
}
/*!
\reimp
\sa QIODevice::close()
*/
void QSerialPort::close()
{
Q_D(QSerialPort);
if (!isOpen()) {
return;
}
QIODevice::close();
d->close();
}
/*!
\property QSerialPort::settingsRestoredOnClose
\brief the flag which allows to restore the previous settings while closing
the serial port.
If this flag is true, the settings will be restored; otherwise not.
The default state of the QSerialPort class is configured to restore the
settings.
*/
void QSerialPort::setSettingsRestoredOnClose(bool restore)
{
Q_D(QSerialPort);
if (d->settingsRestoredOnClose != restore) {
d->settingsRestoredOnClose = restore;
emit settingsRestoredOnCloseChanged(d->settingsRestoredOnClose);
}
}
bool QSerialPort::settingsRestoredOnClose() const
{
Q_D(const QSerialPort);
return d->settingsRestoredOnClose;
}
/*!
\fn void QSerialPort::settingsRestoredOnCloseChanged(bool restore)
This signal is emitted after the flag which allows to restore the
previous settings while closing the serial port has been changed. The new
flag which allows to restore the previous settings while closing the serial
port is passed as \a restore.
\sa QSerialPort::settingsRestoredOnClose
*/
/*!
\property QSerialPort::baudRate
\brief the data baud rate for the desired direction
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. To set the baud rate, use the enumeration
QSerialPort::BaudRate or any positive qint32 value.
\warning Only the AllDirections flag is support for setting this property on
Windows, Windows CE, and Symbian.
\warning Returns equal baud rate in any direction on Windows, Windows CE, and
Symbian.
*/
bool QSerialPort::setBaudRate(qint32 baudRate, Directions dir)
{
Q_D(QSerialPort);
if (d->setBaudRate(baudRate, dir)) {
if (dir & QSerialPort::Input) {
if (d->inputBaudRate != baudRate)
d->inputBaudRate = baudRate;
else
dir &= ~QSerialPort::Input;
}
if (dir & QSerialPort::Output) {
if (d->outputBaudRate != baudRate)
d->outputBaudRate = baudRate;
else
dir &= ~QSerialPort::Output;
}
if (dir)
emit baudRateChanged(baudRate, dir);
return true;
}
return false;
}
qint32 QSerialPort::baudRate(Directions dir) const
{
Q_D(const QSerialPort);
if (dir == QSerialPort::AllDirections)
return d->inputBaudRate == d->outputBaudRate ?
d->inputBaudRate : QSerialPort::UnknownBaud;
return dir & QSerialPort::Input ? d->inputBaudRate : d->outputBaudRate;
}
/*!
\fn void QSerialPort::baudRateChanged(qint32 baudRate, Directions dir)
This signal is emitted after the baud rate has been changed. The new baud
rate is passed as \a baudRate and directions as \a dir.
\sa QSerialPort::baudRate
*/
/*!
\property QSerialPort::dataBits
\brief the data bits in a frame
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.
*/
bool QSerialPort::setDataBits(DataBits dataBits)
{
Q_D(QSerialPort);
if (d->setDataBits(dataBits)) {
if (d->dataBits != dataBits) {
d->dataBits = dataBits;
emit dataBitsChanged(d->dataBits);
}
return true;
}
return false;
}
QSerialPort::DataBits QSerialPort::dataBits() const
{
Q_D(const QSerialPort);
return d->dataBits;
}
/*!
\fn void QSerialPort::dataBitsChanged(DataBits dataBits)
This signal is emitted after the data bits in a frame has been changed. The
new data bits in a frame is passed as \a dataBits.
\sa QSerialPort::dataBits
*/
/*!
\property QSerialPort::parity
\brief the parity checking mode
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.
*/
bool QSerialPort::setParity(Parity parity)
{
Q_D(QSerialPort);
if (d->setParity(parity)) {
if (d->parity != parity) {
d->parity = parity;
emit parityChanged(d->parity);
}
return true;
}
return false;
}
QSerialPort::Parity QSerialPort::parity() const
{
Q_D(const QSerialPort);
return d->parity;
}
/*!
\fn void QSerialPort::parityChanged(Parity parity)
This signal is emitted after the parity checking mode has been changed. The
new parity checking mode is passed as \a parity.
\sa QSerialPort::parity
*/
/*!
\property QSerialPort::stopBits
\brief the number of stop bits in a frame
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.
*/
bool QSerialPort::setStopBits(StopBits stopBits)
{
Q_D(QSerialPort);
if (d->setStopBits(stopBits)) {
if (d->stopBits != stopBits) {
d->stopBits = stopBits;
emit stopBitsChanged(d->stopBits);
}
return true;
}
return false;
}
QSerialPort::StopBits QSerialPort::stopBits() const
{
Q_D(const QSerialPort);
return d->stopBits;
}
/*!
\fn void QSerialPort::stopBitsChanged(StopBits stopBits)
This signal is emitted after the number of stop bits in a frame has been
changed. The new number of stop bits in a frame is passed as \a stopBits.
\sa QSerialPort::stopBits
*/
/*!
\property QSerialPort::flowControl
\brief the desired flow control mode
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.
*/
bool QSerialPort::setFlowControl(FlowControl flow)
{
Q_D(QSerialPort);
if (d->setFlowControl(flow)) {
if (d->flow != flow) {
d->flow = flow;
emit flowControlChanged(d->flow);
}
return true;
}
return false;
}
QSerialPort::FlowControl QSerialPort::flowControl() const
{
Q_D(const QSerialPort);
return d->flow;
}
/*!
\fn void QSerialPort::flowControlChanged(FlowControl flow)
This signal is emitted after the flow control mode has been changed. The
new flow control mode is passed as \a flow.
\sa QSerialPort::flowControl
*/
/*!
\property QSerialPort::dataTerminalReady
\brief the state (high or low) of the line signal DTR
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.
\sa pinoutSignals()
*/
bool QSerialPort::setDataTerminalReady(bool set)
{
Q_D(QSerialPort);
bool retval = d->setDataTerminalReady(set);
if (retval && (d->dataTerminalReady != set)) {
d->dataTerminalReady = set;
emit dataTerminalReadyChanged(set);
}
return retval;
}
bool QSerialPort::isDataTerminalReady()
{
Q_D(const QSerialPort);
return d->pinoutSignals() & QSerialPort::DataTerminalReadySignal;
}
/*!
\fn void QSerialPort::dataTerminalReadyChanged(bool set)
This signal is emitted after the state (high or low) of the line signal DTR
has been changed. The new the state (high or low) of the line signal DTR is
passed as \a set.
\sa QSerialPort::dataTerminalReady
*/
/*!
\property QSerialPort::requestToSend
\brief the state (high or low) of the line signal RTS
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.
\sa pinoutSignals()
*/
bool QSerialPort::setRequestToSend(bool set)
{
Q_D(QSerialPort);
bool retval = d->setRequestToSend(set);
if (retval && (d->requestToSend != set)) {
d->requestToSend = set;
emit requestToSendChanged(set);
}
return retval;
}
bool QSerialPort::isRequestToSend()
{
Q_D(const QSerialPort);
return d->pinoutSignals() & QSerialPort::RequestToSendSignal;
}
/*!
\fn void QSerialPort::requestToSendChanged(bool set)
This signal is emitted after the state (high or low) of the line signal RTS
has been changed. The new the state (high or low) of the line signal RTS is
passed as \a set.
\sa QSerialPort::requestToSend
*/
/*!
Returns the state of the line signals in a bitmap format.
From this result, it is possible to allocate the state of the
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
operating systems cannot provide proper notifications about the changes.
\sa isDataTerminalReady(), isRequestToSend, setDataTerminalReady(),
setRequestToSend()
*/
QSerialPort::PinoutSignals QSerialPort::pinoutSignals()
{
Q_D(const QSerialPort);
return d->pinoutSignals();
}
/*!
This function writes as much as possible from the internal write
buffer to the underlying serial port without blocking. If any data
was written, this function returns true; otherwise returns false.
Call this function for sending the buffered data immediately to the serial
port. The number of bytes successfully written depends on the operating
system. In most cases, this function does not need to be called, because the
QSerialPort class will start sending data automatically once control is
returned to the event loop. In the absence of an event loop, call
waitForBytesWritten() instead.
\sa write(), waitForBytesWritten()
*/
bool QSerialPort::flush()
{
Q_D(QSerialPort);
return d->flush();
}
/*!
Discards all characters from the output or input buffer, depending on
a given direction \a dir. 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.
*/
bool QSerialPort::clear(Directions dir)
{
Q_D(QSerialPort);
if (dir & Input)
d->readBuffer.clear();
if (dir & Output)
d->writeBuffer.clear();
return d->clear(dir);
}
/*!
\reimp
Returns true if no more data is currently available for reading; otherwise
returns false.
This function is most commonly used when reading data from the
serial port in a loop. For example:
\code
// This slot is connected to QSerialPort::readyRead()
void QSerialPortClass::readyReadSlot()
{
while (!port.atEnd()) {
QByteArray data = port.read(100);
....
}
}
\endcode
\sa bytesAvailable(), readyRead()
*/
bool QSerialPort::atEnd() const
{
Q_D(const QSerialPort);
return QIODevice::atEnd() && (!isOpen() || (d->bytesAvailable() == 0));
}
/*!
\property QSerialPort::dataErrorPolicy
\brief the error policy how the process receives the character in case of
parity error detection.
If the setting is successful, returns true; otherwise returns false. The
default policy set is IgnorePolicy.
*/
bool QSerialPort::setDataErrorPolicy(DataErrorPolicy policy)
{
Q_D(QSerialPort);
const bool ret = d->policy == policy || d->setDataErrorPolicy(policy);
if (ret && (d->policy != policy)) {
d->policy = policy;
emit dataErrorPolicyChanged(d->policy);
}
return ret;
}
QSerialPort::DataErrorPolicy QSerialPort::dataErrorPolicy() const
{
Q_D(const QSerialPort);
return d->policy;
}
/*!
\fn void QSerialPort::dataErrorPolicyChanged(DataErrorPolicy policy)
This signal is emitted after the error policy how the process receives the
character in case of parity error detection has been changed. The new error
policy how the process receives the character in case of parity error
detection is passed as \a policy.
\sa QSerialPort::dataErrorPolicy
*/
/*!
\property QSerialPort::error
\brief the error status of the serial port
The I/O device status returns an error code. For example, if open()
returns false, or a read/write operation returns -1, this property can
be used to figure out the reason why the operation failed.
The error code is set to the default QSerialPort::NoError after a call to
clearError()
*/
QSerialPort::SerialPortError QSerialPort::error() const
{
Q_D(const QSerialPort);
return d->error;
}
void QSerialPort::clearError()
{
setError(QSerialPort::NoError);
}
/*!
\fn void QSerialPort::error(SerialPortError error)
This signal is emitted after the error has been changed. The new erroris
passed as \a error.
\sa QSerialPort::error
*/
/*!
Returns the size of the internal read buffer. This limits the
amount of data that the client can receive before calling the read()
or readAll() methods.
A read buffer size of 0 (the default) means that the buffer has
no size limit, ensuring that no data is lost.
\sa setReadBufferSize(), read()
*/
qint64 QSerialPort::readBufferSize() const
{
Q_D(const QSerialPort);
return d->readBufferMaxSize;
}
/*!
Sets the size of QSerialPort's internal read buffer to be \a
size bytes.
If the buffer size is limited to a certain size, QSerialPort
will not buffer more than this size of data. Exceptionally, a buffer
size of 0 means that the read buffer is unlimited and all
incoming data is buffered. This is the default.
This option is useful if the data is only read at certain points
in time (for instance in a real-time streaming application) or if the serial
port should be protected against receiving too much data, which may
eventually causes that the application runs out of memory.
\sa readBufferSize(), read()
*/
void QSerialPort::setReadBufferSize(qint64 size)
{
Q_D(QSerialPort);
if (d->readBufferMaxSize == size)
return;
d->readBufferMaxSize = size;
}
/*!
\reimp
Always returns true. The serial port is a sequential device.
*/
bool QSerialPort::isSequential() const
{
return true;
}
/*!
\reimp
Returns the number of incoming bytes that are waiting to be read.
\sa bytesToWrite(), read()
*/
qint64 QSerialPort::bytesAvailable() const
{
Q_D(const QSerialPort);
return d->bytesAvailable() + QIODevice::bytesAvailable();
}
/*!
\reimp
Returns the number of bytes that are waiting to be written. The
bytes are written when control goes back to the event loop or
when flush() is called.
\sa bytesAvailable(), flush()
*/
qint64 QSerialPort::bytesToWrite() const
{
Q_D(const QSerialPort);
return d->writeBuffer.size() + QIODevice::bytesToWrite();
}
/*!
\reimp
Returns true if a line of data can be read from the serial port;
otherwise returns false.
\sa readLine()
*/
bool QSerialPort::canReadLine() const
{
Q_D(const QSerialPort);
const bool hasLine = (d->bytesAvailable() > 0) && d->readBuffer.canReadLine();
return hasLine || QIODevice::canReadLine();
}
/*!
\reimp
This function blocks until new data is available for reading and the
\l{QIODevice::}{readyRead()} signal has been emitted. The function
will timeout after \a msecs milliseconds.
The function returns true if the readyRead() signal is emitted and
there is new data available for reading; otherwise it returns false
(if an error occurred or the operation timed out).
\sa waitForBytesWritten()
*/
bool QSerialPort::waitForReadyRead(int msecs)
{
Q_D(QSerialPort);
return d->waitForReadyRead(msecs);
}
/*!
\reimp
*/
bool QSerialPort::waitForBytesWritten(int msecs)
{
Q_D(QSerialPort);
return d->waitForBytesWritten(msecs);
}
/*!
Sends a continuous stream of zero bits during a specified period
of time \a duration in msec if the terminal is using asynchronous
serial data. If successful, returns true; otherwise returns false.
If the duration is zero then zero bits are transmitted by at least
0.25 seconds, but no more than 0.5 seconds.
If the duration is non zero then zero bits are transmitted within a certain
period of time depending on the implementation.
\sa setBreakEnabled()
*/
bool QSerialPort::sendBreak(int duration)
{
Q_D(QSerialPort);
return d->sendBreak(duration);
}
/*!
Controls the signal break, depending on the flag \a set.
If successful, returns true; otherwise returns false.
If \a set is true then enables the break transmission; otherwise disables.
\sa sendBreak()
*/
bool QSerialPort::setBreakEnabled(bool set)
{
Q_D(QSerialPort);
return d->setBreakEnabled(set);
}
/*!
\reimp
*/
qint64 QSerialPort::readData(char *data, qint64 maxSize)
{
Q_D(QSerialPort);
return d->readFromBuffer(data, maxSize);
}
/*!
\reimp
*/
qint64 QSerialPort::readLineData(char *data, qint64 maxSize)
{
return QIODevice::readLineData(data, maxSize);
}
/*!
\reimp
*/
qint64 QSerialPort::writeData(const char *data, qint64 maxSize)
{
Q_D(QSerialPort);
return d->writeToBuffer(data, maxSize);
}
void QSerialPort::setError(QSerialPort::SerialPortError serialPortError, const QString &errorString)
{
Q_D(QSerialPort);
d->error = serialPortError;
if (errorString.isNull())
setErrorString(qt_error_string(-1));
else
setErrorString(errorString);
emit error(serialPortError);
}
#include "moc_qserialport.cpp"
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORT_H
#define QSERIALPORT_H
#include <QtCore/qiodevice.h>
#include <qserialportglobal.h>
//#include <QtSerialPort/qserialportglobal.h>
QT_BEGIN_NAMESPACE
class QSerialPortInfo;
class QSerialPortPrivate;
class Q_SERIALPORT_EXPORT QSerialPort : public QIODevice
{
Q_OBJECT
Q_PROPERTY(qint32 baudRate READ baudRate WRITE setBaudRate NOTIFY baudRateChanged)
Q_PROPERTY(DataBits dataBits READ dataBits WRITE setDataBits NOTIFY dataBitsChanged)
Q_PROPERTY(Parity parity READ parity WRITE setParity NOTIFY parityChanged)
Q_PROPERTY(StopBits stopBits READ stopBits WRITE setStopBits NOTIFY stopBitsChanged)
Q_PROPERTY(FlowControl flowControl READ flowControl WRITE setFlowControl NOTIFY flowControlChanged)
Q_PROPERTY(DataErrorPolicy dataErrorPolicy READ dataErrorPolicy WRITE setDataErrorPolicy NOTIFY dataErrorPolicyChanged)
Q_PROPERTY(bool dataTerminalReady READ isDataTerminalReady WRITE setDataTerminalReady NOTIFY dataTerminalReadyChanged)
Q_PROPERTY(bool requestToSend READ isRequestToSend WRITE setRequestToSend NOTIFY requestToSendChanged)
Q_PROPERTY(SerialPortError error READ error RESET clearError NOTIFY error)
Q_PROPERTY(bool settingsRestoredOnClose READ settingsRestoredOnClose WRITE setSettingsRestoredOnClose NOTIFY settingsRestoredOnCloseChanged)
Q_ENUMS( Directions Rate DataBits Parity StopBits FlowControl PinoutSignals DataErrorPolicy SerialPortError )
public:
enum Direction {
Input = 1,
Output = 2,
AllDirections = Input | Output
};
Q_DECLARE_FLAGS(Directions, Direction)
enum BaudRate {
Baud1200 = 1200,
Baud2400 = 2400,
Baud4800 = 4800,
Baud9600 = 9600,
Baud19200 = 19200,
Baud38400 = 38400,
Baud57600 = 57600,
Baud115200 = 115200,
UnknownBaud = -1
};
enum DataBits {
Data5 = 5,
Data6 = 6,
Data7 = 7,
Data8 = 8,
UnknownDataBits = -1
};
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
enum StopBits {
OneStop = 1,
OneAndHalfStop = 3,
TwoStop = 2,
UnknownStopBits = -1
};
enum FlowControl {
NoFlowControl,
HardwareControl,
SoftwareControl,
UnknownFlowControl = -1
};
enum PinoutSignal {
NoSignal = 0x00,
TransmittedDataSignal = 0x01,
ReceivedDataSignal = 0x02,
DataTerminalReadySignal = 0x04,
DataCarrierDetectSignal = 0x08,
DataSetReadySignal = 0x10,
RingIndicatorSignal = 0x20,
RequestToSendSignal = 0x40,
ClearToSendSignal = 0x80,
SecondaryTransmittedDataSignal = 0x100,
SecondaryReceivedDataSignal = 0x200
};
Q_DECLARE_FLAGS(PinoutSignals, PinoutSignal)
enum DataErrorPolicy {
SkipPolicy,
PassZeroPolicy,
IgnorePolicy,
StopReceivingPolicy,
UnknownPolicy = -1
};
enum SerialPortError {
NoError,
DeviceNotFoundError,
PermissionError,
OpenError,
ParityError,
FramingError,
BreakConditionError,
WriteError,
ReadError,
ResourceError,
UnsupportedOperationError,
UnknownError
};
explicit QSerialPort(QObject *parent = 0);
explicit QSerialPort(const QString &name, QObject *parent = 0);
explicit QSerialPort(const QSerialPortInfo &info, QObject *parent = 0);
virtual ~QSerialPort();
void setPortName(const QString &name);
QString portName() const;
void setPort(const QSerialPortInfo &info);
bool open(OpenMode mode) Q_DECL_OVERRIDE;
void close() Q_DECL_OVERRIDE;
void setSettingsRestoredOnClose(bool restore);
bool settingsRestoredOnClose() const;
bool setBaudRate(qint32 baudRate, Directions dir = AllDirections);
qint32 baudRate(Directions dir = AllDirections) const;
bool setDataBits(DataBits dataBits);
DataBits dataBits() const;
bool setParity(Parity parity);
Parity parity() const;
bool setStopBits(StopBits stopBits);
StopBits stopBits() const;
bool setFlowControl(FlowControl flow);
FlowControl flowControl() const;
bool setDataTerminalReady(bool set);
bool isDataTerminalReady();
bool setRequestToSend(bool set);
bool isRequestToSend();
PinoutSignals pinoutSignals();
bool flush();
bool clear(Directions dir = AllDirections);
bool atEnd() const Q_DECL_OVERRIDE;
bool setDataErrorPolicy(DataErrorPolicy policy = IgnorePolicy);
DataErrorPolicy dataErrorPolicy() const;
SerialPortError error() const;
void clearError();
qint64 readBufferSize() const;
void setReadBufferSize(qint64 size);
bool isSequential() const Q_DECL_OVERRIDE;
qint64 bytesAvailable() const Q_DECL_OVERRIDE;
qint64 bytesToWrite() const Q_DECL_OVERRIDE;
bool canReadLine() const Q_DECL_OVERRIDE;
bool waitForReadyRead(int msecs) Q_DECL_OVERRIDE;
bool waitForBytesWritten(int msecs) Q_DECL_OVERRIDE;
bool sendBreak(int duration = 0);
bool setBreakEnabled(bool set = true);
Q_SIGNALS:
void baudRateChanged(qint32 baudRate, QSerialPort::Directions dir);
void dataBitsChanged(QSerialPort::DataBits dataBits);
void parityChanged(QSerialPort::Parity parity);
void stopBitsChanged(QSerialPort::StopBits stopBits);
void flowControlChanged(QSerialPort::FlowControl flow);
void dataErrorPolicyChanged(QSerialPort::DataErrorPolicy policy);
void dataTerminalReadyChanged(bool set);
void requestToSendChanged(bool set);
void error(QSerialPort::SerialPortError serialPortError);
void settingsRestoredOnCloseChanged(bool restore);
protected:
qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
qint64 readLineData(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
qint64 writeData(const char *data, qint64 maxSize) Q_DECL_OVERRIDE;
private:
void setError(QSerialPort::SerialPortError error, const QString &errorString = QString());
QSerialPortPrivate * const d_ptr;
Q_DECLARE_PRIVATE(QSerialPort)
Q_DISABLE_COPY(QSerialPort)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QSerialPort::PinoutSignals)
QT_END_NAMESPACE
#endif // QSERIALPORT_H
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORT_P_H
#define QSERIALPORT_P_H
#include "qserialport.h"
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <private/qringbuffer_p.h>
#else
#include "qt4support/qringbuffer_p.h"
#endif
QT_BEGIN_NAMESPACE
class QSerialPortPrivateData
{
Q_DECLARE_PUBLIC(QSerialPort)
public:
enum IoConstants {
ReadChunkSize = 512,
WriteChunkSize = 512
};
QSerialPortPrivateData(QSerialPort *q);
int timeoutValue(int msecs, int elapsed);
qint64 readBufferMaxSize;
QRingBuffer readBuffer;
QRingBuffer writeBuffer;
QSerialPort::SerialPortError error;
QString systemLocation;
qint32 inputBaudRate;
qint32 outputBaudRate;
QSerialPort::DataBits dataBits;
QSerialPort::Parity parity;
QSerialPort::StopBits stopBits;
QSerialPort::FlowControl flow;
QSerialPort::DataErrorPolicy policy;
bool dataTerminalReady;
bool requestToSend;
bool settingsRestoredOnClose;
QSerialPort * const q_ptr;
};
QT_END_NAMESPACE
#endif // QSERIALPORT_P_H
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialport_symbian_p.h"
#include <QtCore/qmap.h>
#include <e32base.h>
//#include <e32test.h>
#include <f32file.h>
QT_BEGIN_NAMESPACE
// Physical device driver.
#ifdef __WINS__
_LIT(KPddName, "ECDRV");
#else // defined (__EPOC32__)
_LIT(KPddName, "EUART");
#endif
// Logical device driver.
_LIT(KLddName,"ECOMM");
// Modules names.
_LIT(KRS232ModuleName, "ECUART");
_LIT(KBluetoothModuleName, "BTCOMM");
_LIT(KInfraRedModuleName, "IRCOMM");
_LIT(KACMModuleName, "ECACM");
// Return false on error load.
static bool loadDevices()
{
TInt r = KErrNone;
#ifdef __WINS__
RFs fileServer;
r = User::LeaveIfError(fileServer.Connect());
if (r != KErrNone)
return false;
fileServer.Close ();
#endif
r = User::LoadPhysicalDevice(KPddName);
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
r = User::LoadLogicalDevice(KLddName);
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
#ifndef __WINS__
r = StartC32();
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
#endif
return true;
}
QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q)
: QSerialPortPrivateData(q)
, errnum(KErrNone)
{
}
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
// FIXME: Maybe need added check an ReadWrite open mode?
Q_UNUSED(mode)
if (!loadDevices()) {
q_ptr->setError(QSerialPort::UnknownError);
return false;
}
RCommServ server;
errnum = server.Connect();
if (errnum != KErrNone) {
q_ptr->setError(decodeSystemError());
return false;
}
if (systemLocation.contains("BTCOMM"))
errnum = server.LoadCommModule(KBluetoothModuleName);
else if (systemLocation.contains("IRCOMM"))
errnum = server.LoadCommModule(KInfraRedModuleName);
else if (systemLocation.contains("ACM"))
errnum = server.LoadCommModule(KACMModuleName);
else
errnum = server.LoadCommModule(KRS232ModuleName);
if (errnum != KErrNone) {
q_ptr->setError(decodeSystemError());
return false;
}
// In Symbian OS port opening only in R/W mode?
TPtrC portName(static_cast<const TUint16*>(systemLocation.utf16()), systemLocation.length());
errnum = descriptor.Open(server, portName, ECommExclusive);
if (errnum != KErrNone) {
q_ptr->setError(decodeSystemError());
return false;
}
// Save current port settings.
errnum = descriptor.Config(restoredSettings);
if (errnum != KErrNone) {
q_ptr->setError(decodeSystemError());
return false;
}
detectDefaultSettings();
return true;
}
void QSerialPortPrivate::close()
{
if (settingsRestoredOnClose)
descriptor.SetConfig(restoredSettings);
descriptor.Close();
}
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const
{
QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
TUint signalMask = 0;
descriptor.Signals(signalMask);
if (signalMask & KSignalCTS)
ret |= QSerialPort::ClearToSendSignal;
if (signalMask & KSignalDSR)
ret |= QSerialPort::DataSetReadySignal;
if (signalMask & KSignalDCD)
ret |= QSerialPort::DataCarrierDetectSignal;
if (signalMask & KSignalRNG)
ret |= QSerialPort::RingIndicatorSignal;
if (signalMask & KSignalRTS)
ret |= QSerialPort::RequestToSendSignal;
if (signalMask & KSignalDTR)
ret |= QSerialPort::DataTerminalReadySignal;
//if (signalMask & KSignalBreak)
// ret |=
return ret;
}
bool QSerialPortPrivate::setDataTerminalReady(bool set)
{
TInt r;
if (set)
r = descriptor.SetSignalsToMark(KSignalDTR);
else
r = descriptor.SetSignalsToSpace(KSignalDTR);
return r == KErrNone;
}
bool QSerialPortPrivate::setRequestToSend(bool set)
{
TInt r;
if (set)
r = descriptor.SetSignalsToMark(KSignalRTS);
else
r = descriptor.SetSignalsToSpace(KSignalRTS);
return r == KErrNone;
}
bool QSerialPortPrivate::flush()
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::clear(QSerialPort::Directions dir)
{
TUint flags = 0;
if (dir & QSerialPort::Input)
flags |= KCommResetRx;
if (dir & QSerialPort::Output)
flags |= KCommResetTx;
TInt r = descriptor.ResetBuffers(flags);
return r == KErrNone;
}
bool QSerialPortPrivate::sendBreak(int duration)
{
TRequestStatus status;
descriptor.Break(status, TTimeIntervalMicroSeconds32(duration * 1000));
return false;
}
bool QSerialPortPrivate::setBreakEnabled(bool set)
{
// TODO: Implement me
return false;
}
qint64 QSerialPortPrivate::systemInputQueueSize () const
{
return descriptor.QueryReceiveBuffer();
}
qint64 QSerialPortPrivate::systemOutputQueueSize () const
{
// TODO: Implement me
return 0;
}
qint64 QSerialPortPrivate::bytesAvailable() const
{
return readBuffer.size();
}
qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
{
// TODO: Implement me
return -1;
}
qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
{
// TODO: Implement me
return -1;
}
bool QSerialPortPrivate::waitForReadyRead(int msec)
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msec)
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir)
{
if (dir != QSerialPort::AllDirections) {
q_ptr->setError(QSerialPort::UnsupportedOperationError);
return false;
}
baudRate = settingFromBaudRate(baudRate);
if (baudRate)
currentSettings().iRate = static_cast<TBps>(baudRate);
else {
q_ptr->setError(QSerialPort::UnsupportedOperationError);
return false;
}
return updateCommConfig();
}
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
switch (dataBits) {
case QSerialPort::Data5:
currentSettings().iDataBits = EData5;
break;
case QSerialPort::Data6:
currentSettings().iDataBits = EData6;
break;
case QSerialPort::Data7:
currentSettings().iDataBits = EData7;
break;
case QSerialPort::Data8:
currentSettings().iDataBits = EData8;
break;
default:
currentSettings().iDataBits = EData8;
break;
}
return updateCommConfig();
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
switch (parity) {
case QSerialPort::NoParity:
currentSettings().iParity = EParityNone;
break;
case QSerialPort::EvenParity:
currentSettings().iParity = EParityEven;
break;
case QSerialPort::OddParity:
currentSettings().iParity = EParityOdd;
break;
case QSerialPort::MarkParity:
currentSettings().iParity = EParityMark;
break;
case QSerialPort::SpaceParity:
currentSettings().iParity = EParitySpace;
break;
default:
currentSettings().iParity = EParityNone;
break;
}
return updateCommConfig();
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
switch (stopBits) {
case QSerialPort::OneStop:
currentSettings().iStopBits = EStop1;
break;
case QSerialPort::TwoStop:
currentSettings().iStopBits = EStop2;
break;
default:
currentSettings().iStopBits = EStop1;
break;
}
return updateCommConfig();
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow)
{
switch (flow) {
case QSerialPort::NoFlowControl:
currentSettings().iHandshake = KConfigFailDSR;
break;
case QSerialPort::HardwareControl:
currentSettings().iHandshake = KConfigObeyCTS | KConfigFreeRTS;
break;
case QSerialPort::SoftwareControl:
currentSettings().iHandshake = KConfigObeyXoff | KConfigSendXoff;
break;
default:
currentSettings().iHandshake = KConfigFailDSR;
break;
}
return updateCommConfig();
}
bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::notifyRead()
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::notifyWrite()
{
// TODO: Implement me
return false;
}
bool QSerialPortPrivate::updateCommConfig()
{
if (descriptor.SetConfig(currentSettings) != KErrNone) {
q_ptr->setError(QSerialPort::UnsupportedOperationError);
return false;
}
return true;
}
void QSerialPortPrivate::detectDefaultSettings()
{
// Detect baud rate.
inputBaudRate = baudRateFromSetting(currentSettings().iRate);
outputBaudRate = inputBaudRate;
// Detect databits.
switch (currentSettings().iDataBits) {
case EData5:
dataBits = QSerialPort::Data5;
break;
case EData6:
dataBits = QSerialPort::Data6;
break;
case EData7:
dataBits = QSerialPort::Data7;
break;
case EData8:
dataBits = QSerialPort::Data8;
break;
default:
dataBits = QSerialPort::UnknownDataBits;
break;
}
// Detect parity.
switch (currentSettings().iParity) {
case EParityNone:
parity = QSerialPort::NoParity;
break;
case EParityEven:
parity = QSerialPort::EvenParity;
break;
case EParityOdd:
parity = QSerialPort::OddParity;
break;
case EParityMark:
parity = QSerialPort::MarkParity;
break;
case EParitySpace:
parity = QSerialPort::SpaceParity;
break;
default:
parity = QSerialPort::UnknownParity;
break;
}
// Detect stopbits.
switch (currentSettings().iStopBits) {
case EStop1:
stopBits = QSerialPort::OneStop;
break;
case EStop2:
stopBits = QSerialPort::TwoStop;
break;
default:
stopBits = QSerialPort::UnknownStopBits;
break;
}
// Detect flow control.
if ((currentSettings().iHandshake & (KConfigObeyXoff | KConfigSendXoff))
== (KConfigObeyXoff | KConfigSendXoff))
flow = QSerialPort::SoftwareControl;
else if ((currentSettings().iHandshake & (KConfigObeyCTS | KConfigFreeRTS))
== (KConfigObeyCTS | KConfigFreeRTS))
flow = QSerialPort::HardwareControl;
else if (currentSettings().iHandshake & KConfigFailDSR)
flow = QSerialPort::NoFlowControl;
else
flow = QSerialPort::UnknownFlowControl;
}
QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const
{
QSerialPort::SerialPortError error;
switch (errnum) {
case KErrPermissionDenied:
error = QSerialPort::DeviceNotFoundError;
break;
case KErrLocked:
error = QSerialPort::PermissionError;
break;
case KErrAccessDenied:
error = QSerialPort::PermissionError;
break;
default:
error = QSerialPort::UnknownError;
break;
}
return error;
}
bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut)
{
// FIXME: I'm not sure in implementation this method.
// Someone needs to check and correct.
TRequestStatus timerStatus;
TRequestStatus readStatus;
TRequestStatus writeStatus;
if (msecs > 0) {
if (!selectTimer.Handle()) {
if (selectTimer.CreateLocal() != KErrNone)
return false;
}
selectTimer.HighRes(timerStatus, msecs * 1000);
}
if (checkRead)
descriptor.NotifyDataAvailable(readStatus);
if (checkWrite)
descriptor.NotifyOutputEmpty(writeStatus);
enum { STATUSES_COUNT = 3 };
TRequestStatus *statuses[STATUSES_COUNT];
TInt num = 0;
statuses[num++] = &timerStatus;
statuses[num++] = &readStatus;
statuses[num++] = &writeStatus;
User::WaitForNRequest(statuses, num);
bool result = false;
// By timeout?
if (timerStatus != KRequestPending) {
Q_ASSERT(selectForRead);
*selectForRead = false;
Q_ASSERT(selectForWrite);
*selectForWrite = false;
} else {
selectTimer.Cancel();
User::WaitForRequest(timerStatus);
// By read?
if (readStatus != KRequestPending) {
Q_ASSERT(selectForRead);
*selectForRead = true;
}
// By write?
if (writeStatus != KRequestPending) {
Q_ASSERT(selectForWrite);
*selectForWrite = true;
}
if (checkRead)
descriptor.NotifyDataAvailableCancel();
if (checkWrite)
descriptor.NotifyOutputEmptyCancel();
result = true;
}
return result;
}
QString QSerialPortPrivate::portNameToSystemLocation(const QString &port)
{
// Port name is equval to port systemLocation.
return port;
}
QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location)
{
// Port name is equval to port systemLocation.
return location;
}
typedef QMap<qint32, qint32> BaudRateMap;
// This table contains correspondences standard pairs values of
// baud rates that are defined in files
// - d32comm.h for Symbian^3
// - d32public.h for Symbian SR1
static const BaudRateMap createStandardBaudRateMap()
{
BaudRateMap baudRateMap;
baudRateMap.insert(50, EBps50)
baudRateMap.insert(75, EBps75)
baudRateMap.insert(110, EBps110)
baudRateMap.insert(134, EBps134)
baudRateMap.insert(150, EBps150)
baudRateMap.insert(300, EBps300)
baudRateMap.insert(600, EBps600)
baudRateMap.insert(1200, EBps1200)
baudRateMap.insert(1800, EBps1800)
baudRateMap.insert(2000, EBps2000)
baudRateMap.insert(2400, EBps2400)
baudRateMap.insert(3600, EBps3600)
baudRateMap.insert(4800, EBps4800)
baudRateMap.insert(7200, EBps7200)
baudRateMap.insert(9600, EBps9600)
baudRateMap.insert(19200, EBps19200)
baudRateMap.insert(38400, EBps38400)
baudRateMap.insert(57600, EBps57600)
baudRateMap.insert(115200, EBps115200)
baudRateMap.insert(230400, EBps230400)
baudRateMap.insert(460800, EBps460800)
baudRateMap.insert(576000, EBps576000)
baudRateMap.insert(921600, EBps921600)
baudRateMap.insert(1152000, EBps1152000)
// << baudRateMap.insert(1843200, EBps1843200) only for Symbian SR1
baudRateMap.insert(4000000, EBps4000000);
return baudRateMap;
}
static const BaudRateMap& standardBaudRateMap()
{
static const BaudRateMap baudRateMap = createStandardBaudRateMap();
return baudRateMap;
}
qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting)
{
return standardBaudRateMap().key(setting);
}
qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
{
return standardBaudRateMap().value(baudRate);
}
QList<qint32> QSerialPortPrivate::standardBaudRates()
{
return standardBaudRateMap().keys();
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORT_SYMBIAN_P_H
#define QSERIALPORT_SYMBIAN_P_H
#include "qserialport_p.h"
#include <c32comm.h>
QT_BEGIN_NAMESPACE
class QSerialPortPrivate : public QSerialPortPrivateData
{
public:
QSerialPortPrivate(QSerialPort *q);
bool open(QIODevice::OpenMode mode);
void close();
QSerialPort::PinoutSignals pinoutSignals() const;
bool setDataTerminalReady(bool set);
bool setRequestToSend(bool set);
bool flush();
bool clear(QSerialPort::Directions dir);
bool sendBreak(int duration);
bool setBreakEnabled(bool set);
qint64 systemInputQueueSize () const;
qint64 systemOutputQueueSize () const;
qint64 bytesAvailable() const;
qint64 readFromBuffer(char *data, qint64 maxSize);
qint64 writeToBuffer(const char *data, qint64 maxSize);
bool waitForReadyRead(int msec);
bool waitForBytesWritten(int msec);
bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir);
bool setDataBits(QSerialPort::DataBits dataBits);
bool setParity(QSerialPort::Parity parity);
bool setStopBits(QSerialPort::StopBits stopBits);
bool setFlowControl(QSerialPort::FlowControl flowControl);
bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy);
bool notifyRead();
bool notifyWrite();
static QString portNameToSystemLocation(const QString &port);
static QString portNameFromSystemLocation(const QString &location);
static qint32 baudRateFromSetting(qint32 setting);
static qint32 settingFromBaudRate(qint32 baudRate);
static QList<qint32> standardBaudRates();
TCommConfig currentSettings;
TCommConfig restoredSettings;
RComm descriptor;
mutable RTimer selectTimer;
TInt errnum;
private:
bool updateCommConfig();
void detectDefaultSettings();
QSerialPort::SerialPortError decodeSystemError() const;
bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut);
};
QT_END_NAMESPACE
#endif // QSERIALPORT_SYMBIAN_P_H
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialport_unix_p.h"
#include "qttylocker_unix_p.h"
#include <errno.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef Q_OS_MAC
#if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
#include <IOKit/serial/ioss.h>
#endif
#endif
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qsocketnotifier.h>
#include <QtCore/qmap.h>
QT_BEGIN_NAMESPACE
class ReadNotifier : public QSocketNotifier
{
public:
ReadNotifier(QSerialPortPrivate *d, QObject *parent)
: QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
, dptr(d)
{}
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE {
bool ret = QSocketNotifier::event(e);
if (ret)
dptr->readNotification();
return ret;
}
private:
QSerialPortPrivate *dptr;
};
class WriteNotifier : public QSocketNotifier
{
public:
WriteNotifier(QSerialPortPrivate *d, QObject *parent)
: QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
, dptr(d)
{}
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE {
bool ret = QSocketNotifier::event(e);
if (ret)
dptr->writeNotification(QSerialPortPrivateData::WriteChunkSize);
return ret;
}
private:
QSerialPortPrivate *dptr;
};
class ExceptionNotifier : public QSocketNotifier
{
public:
ExceptionNotifier(QSerialPortPrivate *d, QObject *parent)
: QSocketNotifier(d->descriptor, QSocketNotifier::Exception, parent)
, dptr(d)
{}
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE {
bool ret = QSocketNotifier::event(e);
if (ret)
dptr->exceptionNotification();
return ret;
}
private:
QSerialPortPrivate *dptr;
};
QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q)
: QSerialPortPrivateData(q)
, descriptor(-1)
, isCustomBaudRateSupported(false)
, readNotifier(0)
, writeNotifier(0)
, exceptionNotifier(0)
, readPortNotifierCalled(false)
, readPortNotifierState(false)
, readPortNotifierStateSet(false)
, emittedReadyRead(false)
, emittedBytesWritten(false)
{
}
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit();
const char *ptr = portName.constData();
bool byCurrPid = false;
if (QTtyLocker::isLocked(ptr, &byCurrPid)) {
q_ptr->setError(QSerialPort::PermissionError);
return false;
}
int flags = O_NOCTTY | O_NONBLOCK;
switch (mode & QIODevice::ReadWrite) {
case QIODevice::WriteOnly:
flags |= O_WRONLY;
break;
case QIODevice::ReadWrite:
flags |= O_RDWR;
break;
default:
flags |= O_RDONLY;
break;
}
descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags);
if (descriptor == -1) {
q_ptr->setError(decodeSystemError());
return false;
}
::fcntl(descriptor, F_SETFL, FNDELAY);
QTtyLocker::lock(ptr);
if (!QTtyLocker::isLocked(ptr, &byCurrPid)) {
q_ptr->setError(QSerialPort::PermissionError);
return false;
}
#ifdef TIOCEXCL
::ioctl(descriptor, TIOCEXCL);
#endif
if (::tcgetattr(descriptor, &restoredTermios) == -1) {
q_ptr->setError(decodeSystemError());
return false;
}
currentTermios = restoredTermios;
::cfmakeraw(&currentTermios);
currentTermios.c_cflag |= CLOCAL;
currentTermios.c_cc[VTIME] = 0;
currentTermios.c_cc[VMIN] = 0;
if (mode & QIODevice::ReadOnly)
currentTermios.c_cflag |= CREAD;
if (!updateTermios())
return false;
setExceptionNotificationEnabled(true);
if ((flags & O_WRONLY) == 0)
setReadNotificationEnabled(true);
detectDefaultSettings();
return true;
}
void QSerialPortPrivate::close()
{
if (settingsRestoredOnClose) {
::tcsetattr(descriptor, TCSANOW, &restoredTermios);
#ifdef Q_OS_LINUX
if (isCustomBaudRateSupported)
::ioctl(descriptor, TIOCSSERIAL, &restoredSerialInfo);
#endif
}
#ifdef TIOCNXCL
::ioctl(descriptor, TIOCNXCL);
#endif
if (readNotifier) {
readNotifier->setEnabled(false);
readNotifier->deleteLater();
readNotifier = 0;
}
if (writeNotifier) {
writeNotifier->setEnabled(false);
writeNotifier->deleteLater();
writeNotifier = 0;
}
if (exceptionNotifier) {
exceptionNotifier->setEnabled(false);
exceptionNotifier->deleteLater();
exceptionNotifier = 0;
}
::close(descriptor);
QByteArray portName = portNameFromSystemLocation(systemLocation).toLocal8Bit();
const char *ptr = portName.constData();
bool byCurrPid = false;
if (QTtyLocker::isLocked(ptr, &byCurrPid) && byCurrPid)
QTtyLocker::unlock(ptr);
descriptor = -1;
isCustomBaudRateSupported = false;
}
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const
{
int arg = 0;
QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
if (::ioctl(descriptor, TIOCMGET, &arg) == -1) {
q_ptr->setError(decodeSystemError());
return ret;
}
#ifdef TIOCM_LE
if (arg & TIOCM_LE)
ret |= QSerialPort::DataSetReadySignal;
#endif
#ifdef TIOCM_DTR
if (arg & TIOCM_DTR)
ret |= QSerialPort::DataTerminalReadySignal;
#endif
#ifdef TIOCM_RTS
if (arg & TIOCM_RTS)
ret |= QSerialPort::RequestToSendSignal;
#endif
#ifdef TIOCM_ST
if (arg & TIOCM_ST)
ret |= QSerialPort::SecondaryTransmittedDataSignal;
#endif
#ifdef TIOCM_SR
if (arg & TIOCM_SR)
ret |= QSerialPort::SecondaryReceivedDataSignal;
#endif
#ifdef TIOCM_CTS
if (arg & TIOCM_CTS)
ret |= QSerialPort::ClearToSendSignal;
#endif
#ifdef TIOCM_CAR
if (arg & TIOCM_CAR)
ret |= QSerialPort::DataCarrierDetectSignal;
#elif defined TIOCM_CD
if (arg & TIOCM_CD)
ret |= QSerialPort::DataCarrierDetectSignal;
#endif
#ifdef TIOCM_RNG
if (arg & TIOCM_RNG)
ret |= QSerialPort::RingIndicatorSignal;
#elif defined TIOCM_RI
if (arg & TIOCM_RI)
ret |= QSerialPort::RingIndicatorSignal;
#endif
#ifdef TIOCM_DSR
if (arg & TIOCM_DSR)
ret |= QSerialPort::DataSetReadySignal;
#endif
return ret;
}
bool QSerialPortPrivate::setDataTerminalReady(bool set)
{
int status = TIOCM_DTR;
return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1;
}
bool QSerialPortPrivate::setRequestToSend(bool set)
{
int status = TIOCM_RTS;
return ::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) != -1;
}
bool QSerialPortPrivate::flush()
{
return writeNotification() && (::tcdrain(descriptor) != -1);
}
bool QSerialPortPrivate::clear(QSerialPort::Directions dir)
{
return ::tcflush(descriptor, (dir == QSerialPort::AllDirections)
? TCIOFLUSH : (dir & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) != -1;
}
bool QSerialPortPrivate::sendBreak(int duration)
{
return ::tcsendbreak(descriptor, duration) != -1;
}
bool QSerialPortPrivate::setBreakEnabled(bool set)
{
return ::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) != -1;
}
qint64 QSerialPortPrivate::systemInputQueueSize () const
{
int nbytes = 0;
#ifdef TIOCINQ
if (::ioctl(descriptor, TIOCINQ, &nbytes) == -1)
return -1;
#endif
return nbytes;
}
qint64 QSerialPortPrivate::systemOutputQueueSize () const
{
int nbytes = 0;
#ifdef TIOCOUTQ
if (::ioctl(descriptor, TIOCOUTQ, &nbytes) == -1)
return -1;
#endif
return nbytes;
}
qint64 QSerialPortPrivate::bytesAvailable() const
{
return readBuffer.size();
}
qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
{
if (readBuffer.isEmpty())
return 0;
if (maxSize == 1) {
*data = readBuffer.getChar();
if (readBuffer.isEmpty())
setReadNotificationEnabled(true);
return 1;
}
const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
const char *ptr = readBuffer.readPointer();
const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
readBuffer.nextDataBlockSize());
::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
readBuffer.free(bytesToReadFromThisBlock);
}
if (!isReadNotificationEnabled())
setReadNotificationEnabled(true);
if (readSoFar > 0) {
if (readBuffer.isEmpty())
setReadNotificationEnabled(true);
return readSoFar;
}
return readSoFar;
}
qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
{
char *ptr = writeBuffer.reserve(maxSize);
if (maxSize == 1)
*ptr = *data;
else
::memcpy(ptr, data, maxSize);
const qint64 written = maxSize;
if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
setWriteNotificationEnabled(true);
return written;
}
bool QSerialPortPrivate::waitForReadyRead(int msecs)
{
QElapsedTimer stopWatch;
stopWatch.start();
do {
bool readyToRead = false;
bool readyToWrite = false;
bool timedOut = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
q_ptr->setError(decodeSystemError());
return false;
}
if (readyToRead) {
if (readNotification())
return true;
}
if (readyToWrite)
writeNotification(WriteChunkSize);
} while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0);
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msecs)
{
if (writeBuffer.isEmpty())
return false;
QElapsedTimer stopWatch;
stopWatch.start();
forever {
bool readyToRead = false;
bool readyToWrite = false;
bool timedOut = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
timeoutValue(msecs, stopWatch.elapsed()), &timedOut)) {
q_ptr->setError(decodeSystemError());
return false;
}
if (readyToRead && !readNotification())
return false;
if (readyToWrite)
return writeNotification(WriteChunkSize);
}
return false;
}
bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir)
{
bool ret = baudRate > 0;
// prepare section
if (ret) {
const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate);
if (unixBaudRate > 0) {
// try prepate to set standard baud rate
#ifdef Q_OS_LINUX
// prepare to forcefully reset the custom mode
if (isCustomBaudRateSupported) {
//currentSerialInfo.flags |= ASYNC_SPD_MASK;
currentSerialInfo.flags &= ~(ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
currentSerialInfo.custom_divisor = 0;
}
#endif
// prepare to set standard baud rate
ret = !(((dir & QSerialPort::Input) && ::cfsetispeed(&currentTermios, unixBaudRate) < 0)
|| ((dir & QSerialPort::Output) && ::cfsetospeed(&currentTermios, unixBaudRate) < 0));
} else {
// try prepate to set custom baud rate
#ifdef Q_OS_LINUX
// prepare to forcefully set the custom mode
if (isCustomBaudRateSupported) {
currentSerialInfo.flags &= ~ASYNC_SPD_MASK;
currentSerialInfo.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
currentSerialInfo.custom_divisor = currentSerialInfo.baud_base / baudRate;
if (currentSerialInfo.custom_divisor == 0)
currentSerialInfo.custom_divisor = 1;
// for custom mode needed prepare to set B38400 baud rate
ret = (::cfsetspeed(&currentTermios, B38400) != -1);
} else {
ret = false;
}
#elif defined(Q_OS_MAC)
# if defined (MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
// Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
// other than those specified by POSIX. The driver for the underlying serial hardware
// ultimately determines which baud rates can be used. This ioctl sets both the input
// and output speed.
ret = ::ioctl(descriptor, IOSSIOSPEED, &baudRate) != -1;
# else
// others MacOSX version, can't prepare to set custom baud rate
ret = false;
# endif
#else
// others *nix OS, can't prepare to set custom baud rate
ret = false;
#endif
}
}
// finally section
#ifdef Q_OS_LINUX
if (ret && isCustomBaudRateSupported) // finally, set or reset the custom mode
ret = ::ioctl(descriptor, TIOCSSERIAL, &currentSerialInfo) != -1;
#endif
if (ret) // finally, set baud rate
ret = updateTermios();
else
q_ptr->setError(decodeSystemError());
return ret;
}
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
currentTermios.c_cflag &= ~CSIZE;
switch (dataBits) {
case QSerialPort::Data5:
currentTermios.c_cflag |= CS5;
break;
case QSerialPort::Data6:
currentTermios.c_cflag |= CS6;
break;
case QSerialPort::Data7:
currentTermios.c_cflag |= CS7;
break;
case QSerialPort::Data8:
currentTermios.c_cflag |= CS8;
break;
default:
currentTermios.c_cflag |= CS8;
break;
}
return updateTermios();
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
currentTermios.c_iflag &= ~(PARMRK | INPCK);
currentTermios.c_iflag |= IGNPAR;
switch (parity) {
#ifdef CMSPAR
// Here Installation parity only for GNU/Linux where the macro CMSPAR.
case QSerialPort::SpaceParity:
currentTermios.c_cflag &= ~PARODD;
currentTermios.c_cflag |= PARENB | CMSPAR;
break;
case QSerialPort::MarkParity:
currentTermios.c_cflag |= PARENB | CMSPAR | PARODD;
break;
#endif
case QSerialPort::NoParity:
currentTermios.c_cflag &= ~PARENB;
break;
case QSerialPort::EvenParity:
currentTermios.c_cflag &= ~PARODD;
currentTermios.c_cflag |= PARENB;
break;
case QSerialPort::OddParity:
currentTermios.c_cflag |= PARENB | PARODD;
break;
default:
currentTermios.c_cflag |= PARENB;
currentTermios.c_iflag |= PARMRK | INPCK;
currentTermios.c_iflag &= ~IGNPAR;
break;
}
return updateTermios();
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
switch (stopBits) {
case QSerialPort::OneStop:
currentTermios.c_cflag &= ~CSTOPB;
break;
case QSerialPort::TwoStop:
currentTermios.c_cflag |= CSTOPB;
break;
default:
currentTermios.c_cflag &= ~CSTOPB;
break;
}
return updateTermios();
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow)
{
switch (flow) {
case QSerialPort::NoFlowControl:
currentTermios.c_cflag &= ~CRTSCTS;
currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case QSerialPort::HardwareControl:
currentTermios.c_cflag |= CRTSCTS;
currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case QSerialPort::SoftwareControl:
currentTermios.c_cflag &= ~CRTSCTS;
currentTermios.c_iflag |= IXON | IXOFF | IXANY;
break;
default:
currentTermios.c_cflag &= ~CRTSCTS;
currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
}
return updateTermios();
}
bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
{
tcflag_t parmrkMask = PARMRK;
#ifndef CMSPAR
// in space/mark parity emulation also used PARMRK flag
if (parity == QSerialPort::SpaceParity
|| parity == QSerialPort::MarkParity) {
parmrkMask = 0;
}
#endif //CMSPAR
switch (policy) {
case QSerialPort::SkipPolicy:
currentTermios.c_iflag &= ~parmrkMask;
currentTermios.c_iflag |= IGNPAR | INPCK;
break;
case QSerialPort::PassZeroPolicy:
currentTermios.c_iflag &= ~(IGNPAR | parmrkMask);
currentTermios.c_iflag |= INPCK;
break;
case QSerialPort::IgnorePolicy:
currentTermios.c_iflag &= ~INPCK;
break;
case QSerialPort::StopReceivingPolicy:
currentTermios.c_iflag &= ~IGNPAR;
currentTermios.c_iflag |= parmrkMask | INPCK;
break;
default:
currentTermios.c_iflag &= ~INPCK;
break;
}
return updateTermios();
}
bool QSerialPortPrivate::readNotification()
{
// Prevent recursive calls
if (readPortNotifierCalled) {
if (!readPortNotifierStateSet) {
readPortNotifierStateSet = true;
readPortNotifierState = isReadNotificationEnabled();
setReadNotificationEnabled(false);
}
}
readPortNotifierCalled = true;
// Always buffered, read data from the port into the read buffer
qint64 newBytes = readBuffer.size();
qint64 bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1;
if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
bytesToRead = readBufferMaxSize - readBuffer.size();
if (bytesToRead == 0) {
// Buffer is full. User must read data from the buffer
// before we can read more from the port.
return false;
}
}
char *ptr = readBuffer.reserve(bytesToRead);
const qint64 readBytes = readFromPort(ptr, bytesToRead);
if (readBytes <= 0) {
readBuffer.chop(bytesToRead);
return false;
}
readBuffer.chop(bytesToRead - qMax(readBytes, qint64(0)));
newBytes = readBuffer.size() - newBytes;
// If read buffer is full, disable the read port notifier.
if (readBufferMaxSize && readBuffer.size() == readBufferMaxSize)
setReadNotificationEnabled(false);
// only emit readyRead() when not recursing, and only if there is data available
const bool hasData = newBytes > 0;
if (!emittedReadyRead && hasData) {
emittedReadyRead = true;
emit q_ptr->readyRead();
emittedReadyRead = false;
}
if (!hasData)
setReadNotificationEnabled(true);
// reset the read port notifier state if we reentered inside the
// readyRead() connected slot.
if (readPortNotifierStateSet
&& readPortNotifierState != isReadNotificationEnabled()) {
setReadNotificationEnabled(readPortNotifierState);
readPortNotifierStateSet = false;
}
return true;
}
bool QSerialPortPrivate::writeNotification(int maxSize)
{
const int tmp = writeBuffer.size();
if (writeBuffer.isEmpty()) {
setWriteNotificationEnabled(false);
return false;
}
int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize);
const char *ptr = writeBuffer.readPointer();
// Attempt to write it chunk.
qint64 written = writeToPort(ptr, nextSize);
if (written < 0)
return false;
// Remove what we wrote so far.
writeBuffer.free(written);
if (written > 0) {
// Don't emit bytesWritten() recursively.
if (!emittedBytesWritten) {
emittedBytesWritten = true;
emit q_ptr->bytesWritten(written);
emittedBytesWritten = false;
}
}
if (writeBuffer.isEmpty())
setWriteNotificationEnabled(false);
return (writeBuffer.size() < tmp);
}
bool QSerialPortPrivate::exceptionNotification()
{
QSerialPort::SerialPortError error = decodeSystemError();
q_ptr->setError(error);
return true;
}
bool QSerialPortPrivate::updateTermios()
{
if (::tcsetattr(descriptor, TCSANOW, &currentTermios) == -1) {
q_ptr->setError(decodeSystemError());
return false;
}
return true;
}
void QSerialPortPrivate::detectDefaultSettings()
{
// Detect baud rate.
const speed_t inputUnixBaudRate = ::cfgetispeed(&currentTermios);
const speed_t outputUnixBaudRate = ::cfgetospeed(&currentTermios);
bool isCustomBaudRateCurrentSet = false;
#ifdef Q_OS_LINUX
// try detect the ability to support custom baud rate
isCustomBaudRateSupported = ::ioctl(descriptor, TIOCGSERIAL, &currentSerialInfo) != -1
&& ::ioctl(descriptor, TIOCSSERIAL, &currentSerialInfo) != -1;
if (isCustomBaudRateSupported) {
restoredSerialInfo = currentSerialInfo;
// assume that the baud rate is a custom
isCustomBaudRateCurrentSet = inputUnixBaudRate == B38400 && outputUnixBaudRate == B38400;
if (isCustomBaudRateCurrentSet) {
if ((currentSerialInfo.flags & ASYNC_SPD_CUST)
&& currentSerialInfo.custom_divisor > 0) {
// yes, speed is really custom
inputBaudRate = currentSerialInfo.baud_base / currentSerialInfo.custom_divisor;
outputBaudRate = inputBaudRate;
} else {
// no, we were wrong and the speed is a standard 38400 baud
isCustomBaudRateCurrentSet = false;
}
}
}
#else
// other *nix
#endif
if (!isCustomBaudRateSupported || !isCustomBaudRateCurrentSet) {
inputBaudRate = QSerialPortPrivate::baudRateFromSetting(inputUnixBaudRate);
outputBaudRate = QSerialPortPrivate::baudRateFromSetting(outputUnixBaudRate);
}
// Detect databits.
switch (currentTermios.c_cflag & CSIZE) {
case CS5:
dataBits = QSerialPort::Data5;
break;
case CS6:
dataBits = QSerialPort::Data6;
break;
case CS7:
dataBits = QSerialPort::Data7;
break;
case CS8:
dataBits = QSerialPort::Data8;
break;
default:
dataBits = QSerialPort::UnknownDataBits;
break;
}
// Detect parity.
#ifdef CMSPAR
if (currentTermios.c_cflag & CMSPAR) {
parity = currentTermios.c_cflag & PARODD ?
QSerialPort::MarkParity : QSerialPort::SpaceParity;
} else {
#endif
if (currentTermios.c_cflag & PARENB) {
parity = currentTermios.c_cflag & PARODD ?
QSerialPort::OddParity : QSerialPort::EvenParity;
} else {
parity = QSerialPort::NoParity;
}
#ifdef CMSPAR
}
#endif
// Detect stopbits.
stopBits = currentTermios.c_cflag & CSTOPB ?
QSerialPort::TwoStop : QSerialPort::OneStop;
// Detect flow control.
if ((!(currentTermios.c_cflag & CRTSCTS)) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY))))
flow = QSerialPort::NoFlowControl;
else if ((!(currentTermios.c_cflag & CRTSCTS)) && (currentTermios.c_iflag & (IXON | IXOFF | IXANY)))
flow = QSerialPort::SoftwareControl;
else if ((currentTermios.c_cflag & CRTSCTS) && (!(currentTermios.c_iflag & (IXON | IXOFF | IXANY))))
flow = QSerialPort::HardwareControl;
else
flow = QSerialPort::UnknownFlowControl;
}
QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const
{
QSerialPort::SerialPortError error;
switch (errno) {
case ENODEV:
error = QSerialPort::DeviceNotFoundError;
break;
case EACCES:
error = QSerialPort::PermissionError;
break;
case EBUSY:
error = QSerialPort::PermissionError;
break;
case EAGAIN:
error = QSerialPort::ResourceError;
break;
case EIO:
error = QSerialPort::ResourceError;
break;
case EBADF:
error = QSerialPort::ResourceError;
break;
#ifdef Q_OS_MAC
case ENXIO:
error = QSerialPort::ResourceError;
break;
#endif
default:
error = QSerialPort::UnknownError;
break;
}
return error;
}
bool QSerialPortPrivate::isReadNotificationEnabled() const
{
return readNotifier && readNotifier->isEnabled();
}
void QSerialPortPrivate::setReadNotificationEnabled(bool enable)
{
if (readNotifier) {
readNotifier->setEnabled(enable);
} else if (enable) {
readNotifier = new ReadNotifier(this, q_ptr);
readNotifier->setEnabled(true);
}
}
bool QSerialPortPrivate::isWriteNotificationEnabled() const
{
return writeNotifier && writeNotifier->isEnabled();
}
void QSerialPortPrivate::setWriteNotificationEnabled(bool enable)
{
if (writeNotifier) {
writeNotifier->setEnabled(enable);
} else if (enable) {
writeNotifier = new WriteNotifier(this, q_ptr);
writeNotifier->setEnabled(true);
}
}
bool QSerialPortPrivate::isExceptionNotificationEnabled() const
{
return exceptionNotifier && exceptionNotifier->isEnabled();
}
void QSerialPortPrivate::setExceptionNotificationEnabled(bool enable)
{
if (exceptionNotifier) {
exceptionNotifier->setEnabled(enable);
} else if (enable) {
exceptionNotifier = new ExceptionNotifier(this, q_ptr);
exceptionNotifier->setEnabled(true);
}
}
bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut)
{
Q_ASSERT(selectForRead);
Q_ASSERT(selectForWrite);
Q_ASSERT(timedOut);
fd_set fdread;
FD_ZERO(&fdread);
if (checkRead)
FD_SET(descriptor, &fdread);
fd_set fdwrite;
FD_ZERO(&fdwrite);
if (checkWrite)
FD_SET(descriptor, &fdwrite);
struct timeval tv;
tv.tv_sec = msecs / 1000;
tv.tv_usec = (msecs % 1000) * 1000;
int ret = ::select(descriptor + 1, &fdread, &fdwrite, 0, msecs < 0 ? 0 : &tv);
if (ret < 0)
return false;
if (ret == 0) {
*timedOut = true;
return false;
}
*selectForRead = FD_ISSET(descriptor, &fdread);
*selectForWrite = FD_ISSET(descriptor, &fdwrite);
return ret;
}
qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
{
qint64 bytesRead = 0;
#if defined (CMSPAR)
if (parity == QSerialPort::NoParity
|| policy != QSerialPort::StopReceivingPolicy) {
#else
if (parity != QSerialPort::MarkParity
&& parity != QSerialPort::SpaceParity) {
#endif
bytesRead = ::read(descriptor, data, maxSize);
} else {// Perform parity emulation.
bytesRead = readPerChar(data, maxSize);
}
if (bytesRead <= 0) {
QSerialPort::SerialPortError error = decodeSystemError();
if (error != QSerialPort::ResourceError)
error = QSerialPort::ReadError;
q_ptr->setError(error);
}
return bytesRead;
}
qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
{
qint64 bytesWritten = 0;
#if defined (CMSPAR)
bytesWritten = ::write(descriptor, data, maxSize);
#else
if (parity != QSerialPort::MarkParity
&& parity != QSerialPort::SpaceParity) {
bytesWritten = ::write(descriptor, data, maxSize);
} else {// Perform parity emulation.
bytesWritten = writePerChar(data, maxSize);
}
#endif
if (bytesWritten < 0) {
QSerialPort::SerialPortError error = decodeSystemError();
if (error != QSerialPort::ResourceError)
error = QSerialPort::WriteError;
q_ptr->setError(error);
}
return bytesWritten;
}
static inline bool evenParity(quint8 c)
{
c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0)
c ^= c >> 2; //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)]
c ^= c >> 1;
return c & 1; //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0)
}
#ifndef CMSPAR
qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
{
qint64 ret = 0;
quint8 const charMask = (0xFF >> (8 - dataBits));
while (ret < maxSize) {
bool par = evenParity(*data & charMask);
// False if need EVEN, true if need ODD.
par ^= parity == QSerialPort::MarkParity;
if (par ^ (currentTermios.c_cflag & PARODD)) { // Need switch parity mode?
currentTermios.c_cflag ^= PARODD;
flush(); //force sending already buffered data, because updateTermios() cleares buffers
//todo: add receiving buffered data!!!
if (!updateTermios())
break;
}
int r = ::write(descriptor, data, 1);
if (r < 0)
return -1;
if (r > 0) {
data += r;
ret += r;
}
}
return ret;
}
#endif //CMSPAR
qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize)
{
qint64 ret = 0;
quint8 const charMask = (0xFF >> (8 - dataBits));
// 0 - prefix not started,
// 1 - received 0xFF,
// 2 - received 0xFF and 0x00
int prefix = 0;
while (ret < maxSize) {
qint64 r = ::read(descriptor, data, 1);
if (r < 0) {
if (errno == EAGAIN) // It is ok for nonblocking mode.
break;
return -1;
}
if (r == 0)
break;
bool par = true;
switch (prefix) {
case 2: // Previously received both 0377 and 0.
par = false;
prefix = 0;
break;
case 1: // Previously received 0377.
if (*data == '\0') {
++prefix;
continue;
}
prefix = 0;
break;
default:
if (*data == '\377') {
prefix = 1;
continue;
}
break;
}
// Now: par contains parity ok or error, *data contains received character
par ^= evenParity(*data & charMask); //par contains parity bit value for EVEN mode
par ^= (currentTermios.c_cflag & PARODD); //par contains parity bit value for current mode
if (par ^ (parity == QSerialPort::SpaceParity)) { //if parity error
switch (policy) {
case QSerialPort::SkipPolicy:
continue; //ignore received character
case QSerialPort::StopReceivingPolicy:
if (parity != QSerialPort::NoParity)
q_ptr->setError(QSerialPort::ParityError);
else
q_ptr->setError(*data == '\0' ?
QSerialPort::BreakConditionError : QSerialPort::FramingError);
return ++ret; //abort receiving
break;
case QSerialPort::UnknownPolicy:
// Unknown error policy is used! Falling back to PassZeroPolicy
case QSerialPort::PassZeroPolicy:
*data = '\0'; //replace received character by zero
break;
case QSerialPort::IgnorePolicy:
break; //ignore error and pass received character
}
}
++data;
++ret;
}
return ret;
}
#ifdef Q_OS_MAC
static const QLatin1String defaultFilePathPrefix("/dev/cu.");
static const QLatin1String unusedFilePathPrefix("/dev/tty.");
#else
static const QLatin1String defaultFilePathPrefix("/dev/");
#endif
QString QSerialPortPrivate::portNameToSystemLocation(const QString &port)
{
QString ret = port;
#ifdef Q_OS_MAC
ret.remove(unusedFilePathPrefix);
#endif
if (!ret.contains(defaultFilePathPrefix))
ret.prepend(defaultFilePathPrefix);
return ret;
}
QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location)
{
QString ret = location;
#ifdef Q_OS_MAC
ret.remove(unusedFilePathPrefix);
#endif
ret.remove(defaultFilePathPrefix);
return ret;
}
typedef QMap<qint32, qint32> BaudRateMap;
// The OS specific defines can be found in termios.h
static const BaudRateMap createStandardBaudRateMap()
{
BaudRateMap baudRateMap;
#ifdef B50
baudRateMap.insert(50, B50);
#endif
#ifdef B75
baudRateMap.insert(75, B75);
#endif
#ifdef B110
baudRateMap.insert(110, B110);
#endif
#ifdef B134
baudRateMap.insert(134, B134);
#endif
#ifdef B150
baudRateMap.insert(150, B150);
#endif
#ifdef B200
baudRateMap.insert(200, B200);
#endif
#ifdef B300
baudRateMap.insert(300, B300);
#endif
#ifdef B600
baudRateMap.insert(600, B600);
#endif
#ifdef B1200
baudRateMap.insert(1200, B1200);
#endif
#ifdef B1800
baudRateMap.insert(1800, B1800);
#endif
#ifdef B2400
baudRateMap.insert(2400, B2400);
#endif
#ifdef B4800
baudRateMap.insert(4800, B4800);
#endif
#ifdef B9600
baudRateMap.insert(9600, B9600);
#endif
#ifdef B19200
baudRateMap.insert(19200, B19200);
#endif
#ifdef B38400
baudRateMap.insert(38400, B38400);
#endif
#ifdef B57600
baudRateMap.insert(57600, B57600);
#endif
#ifdef B115200
baudRateMap.insert(115200, B115200);
#endif
#ifdef B230400
baudRateMap.insert(230400, B230400);
#endif
#ifdef B460800
baudRateMap.insert(460800, B460800);
#endif
#ifdef B500000
baudRateMap.insert(500000, B500000);
#endif
#ifdef B576000
baudRateMap.insert(576000, B576000);
#endif
#ifdef B921600
baudRateMap.insert(921600, B921600);
#endif
#ifdef B1000000
baudRateMap.insert(1000000, B1000000);
#endif
#ifdef B1152000
baudRateMap.insert(1152000, B1152000);
#endif
#ifdef B1500000
baudRateMap.insert(1500000, B1500000);
#endif
#ifdef B2000000
baudRateMap.insert(2000000, B2000000);
#endif
#ifdef B2500000
baudRateMap.insert(2500000, B2500000);
#endif
#ifdef B3000000
baudRateMap.insert(3000000, B3000000);
#endif
#ifdef B3500000
baudRateMap.insert(3500000, B3500000);
#endif
#ifdef B4000000
baudRateMap.insert(4000000, B4000000);
#endif
return baudRateMap;
}
static const BaudRateMap& standardBaudRateMap()
{
static const BaudRateMap baudRateMap = createStandardBaudRateMap();
return baudRateMap;
}
qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting)
{
return standardBaudRateMap().key(setting);
}
qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
{
return standardBaudRateMap().value(baudRate);
}
QList<qint32> QSerialPortPrivate::standardBaudRates()
{
return standardBaudRateMap().keys();
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORT_UNIX_P_H
#define QSERIALPORT_UNIX_P_H
#include "qserialport_p.h"
#include <limits.h>
#include <termios.h>
#ifdef Q_OS_LINUX
# include <linux/serial.h>
#endif
QT_BEGIN_NAMESPACE
class QSocketNotifier;
class QSerialPortPrivate : public QSerialPortPrivateData
{
public:
QSerialPortPrivate(QSerialPort *q);
bool open(QIODevice::OpenMode mode);
void close();
QSerialPort::PinoutSignals pinoutSignals() const;
bool setDataTerminalReady(bool set);
bool setRequestToSend(bool set);
bool flush();
bool clear(QSerialPort::Directions dir);
bool sendBreak(int duration);
bool setBreakEnabled(bool set);
qint64 systemInputQueueSize () const;
qint64 systemOutputQueueSize () const;
qint64 bytesAvailable() const;
qint64 readFromBuffer(char *data, qint64 maxSize);
qint64 writeToBuffer(const char *data, qint64 maxSize);
bool waitForReadyRead(int msecs);
bool waitForBytesWritten(int msecs);
bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir);
bool setDataBits(QSerialPort::DataBits dataBits);
bool setParity(QSerialPort::Parity parity);
bool setStopBits(QSerialPort::StopBits stopBits);
bool setFlowControl(QSerialPort::FlowControl flow);
bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy);
bool readNotification();
bool writeNotification(int maxSize = INT_MAX);
bool exceptionNotification();
static QString portNameToSystemLocation(const QString &port);
static QString portNameFromSystemLocation(const QString &location);
static qint32 baudRateFromSetting(qint32 setting);
static qint32 settingFromBaudRate(qint32 baudRate);
static QList<qint32> standardBaudRates();
struct termios currentTermios;
struct termios restoredTermios;
#ifdef Q_OS_LINUX
struct serial_struct currentSerialInfo;
struct serial_struct restoredSerialInfo;
#endif
int descriptor;
bool isCustomBaudRateSupported;
QSocketNotifier *readNotifier;
QSocketNotifier *writeNotifier;
QSocketNotifier *exceptionNotifier;
bool readPortNotifierCalled;
bool readPortNotifierState;
bool readPortNotifierStateSet;
bool emittedReadyRead;
bool emittedBytesWritten;
private:
bool updateTermios();
void detectDefaultSettings();
QSerialPort::SerialPortError decodeSystemError() const;
bool isReadNotificationEnabled() const;
void setReadNotificationEnabled(bool enable);
bool isWriteNotificationEnabled() const;
void setWriteNotificationEnabled(bool enable);
bool isExceptionNotificationEnabled() const;
void setExceptionNotificationEnabled(bool enable);
bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut);
qint64 readFromPort(char *data, qint64 maxSize);
qint64 writeToPort(const char *data, qint64 maxSize);
#ifndef CMSPAR
qint64 writePerChar(const char *data, qint64 maxSize);
#endif
qint64 readPerChar(char *data, qint64 maxSize);
};
QT_END_NAMESPACE
#endif // QSERIALPORT_UNIX_P_H
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialport_win_p.h"
#ifndef Q_OS_WINCE
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qvector.h>
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#include <QtCore/qwineventnotifier.h>
#else
#include "qt4support/qwineventnotifier_p.h"
#endif
#ifndef CTL_CODE
# define CTL_CODE(DeviceType, Function, Method, Access) ( \
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)
#endif
#ifndef FILE_DEVICE_SERIAL_PORT
# define FILE_DEVICE_SERIAL_PORT 27
#endif
#ifndef METHOD_BUFFERED
# define METHOD_BUFFERED 0
#endif
#ifndef FILE_ANY_ACCESS
# define FILE_ANY_ACCESS 0x00000000
#endif
#ifndef IOCTL_SERIAL_GET_DTRRTS
# define IOCTL_SERIAL_GET_DTRRTS \
CTL_CODE(FILE_DEVICE_SERIAL_PORT, 30, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
#ifndef SERIAL_DTR_STATE
# define SERIAL_DTR_STATE 0x00000001
#endif
#ifndef SERIAL_RTS_STATE
# define SERIAL_RTS_STATE 0x00000002
#endif
QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINCE
class AbstractOverlappedEventNotifier : public QWinEventNotifier
{
public:
enum Type { CommEvent, ReadCompletionEvent, WriteCompletionEvent };
AbstractOverlappedEventNotifier(QSerialPortPrivate *d, Type type, bool manual, QObject *parent)
: QWinEventNotifier(parent), dptr(d), t(type) {
::memset(&o, 0, sizeof(o));
o.hEvent = ::CreateEvent(NULL, manual, FALSE, NULL);
setHandle(o.hEvent);
dptr->notifiers[o.hEvent] = this;
}
virtual bool processCompletionRoutine() = 0;
virtual ~AbstractOverlappedEventNotifier() {
setEnabled(false);
::CancelIo(o.hEvent);
::CloseHandle(o.hEvent);
}
Type type() const { return t; }
OVERLAPPED *overlappedPointer() { return &o; }
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE {
const bool ret = QWinEventNotifier::event(e);
processCompletionRoutine();
return ret;
}
QSerialPortPrivate *dptr;
Type t;
OVERLAPPED o;
};
class CommOverlappedEventNotifier : public AbstractOverlappedEventNotifier
{
public:
CommOverlappedEventNotifier(QSerialPortPrivate *d, DWORD eventMask, QObject *parent)
: AbstractOverlappedEventNotifier(d, CommEvent, false, parent)
, originalEventMask(eventMask), triggeredEventMask(0) {
::SetCommMask(dptr->descriptor, originalEventMask);
startWaitCommEvent();
}
void startWaitCommEvent() { ::WaitCommEvent(dptr->descriptor, &triggeredEventMask, &o); }
bool processCompletionRoutine() Q_DECL_OVERRIDE {
DWORD numberOfBytesTransferred = 0;
::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE);
bool error = false;
// Check for unexpected event. This event triggered when pulled previously
// opened device from the system, when opened as for not to read and not to
// write options and so forth.
if (triggeredEventMask == 0)
error = true;
// Workaround for standard CDC ACM serial ports, for which triggered an
// unexpected event EV_TXEMPTY at data transmission.
if ((originalEventMask & triggeredEventMask) == 0) {
if ((triggeredEventMask & EV_TXEMPTY) == 0)
error = true;
}
// Start processing a caught error.
if (error || (EV_ERR & triggeredEventMask))
dptr->processIoErrors(error);
if (!error)
dptr->startAsyncRead();
return !error;
}
private:
DWORD originalEventMask;
DWORD triggeredEventMask;
};
class ReadOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier
{
public:
ReadOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent)
: AbstractOverlappedEventNotifier(d, ReadCompletionEvent, false, parent) {}
bool processCompletionRoutine() Q_DECL_OVERRIDE {
DWORD numberOfBytesTransferred = 0;
::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE);
bool ret = dptr->completeAsyncRead(numberOfBytesTransferred);
// start async read for possible remainder into driver queue
if (ret && (numberOfBytesTransferred > 0) && (dptr->policy == QSerialPort::IgnorePolicy)) {
dptr->startAsyncRead();
} else { // driver queue is emplty, so startup wait comm event
CommOverlappedEventNotifier *n =
reinterpret_cast<CommOverlappedEventNotifier *>(dptr->lookupCommEventNotifier());
if (n)
n->startWaitCommEvent();
}
return ret;
}
};
class WriteOverlappedCompletionNotifier : public AbstractOverlappedEventNotifier
{
public:
WriteOverlappedCompletionNotifier(QSerialPortPrivate *d, QObject *parent)
: AbstractOverlappedEventNotifier(d, WriteCompletionEvent, false, parent) {}
bool processCompletionRoutine() Q_DECL_OVERRIDE {
setEnabled(false);
DWORD numberOfBytesTransferred = 0;
::GetOverlappedResult(dptr->descriptor, &o, &numberOfBytesTransferred, FALSE);
return dptr->completeAsyncWrite(numberOfBytesTransferred);
}
};
QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q)
: QSerialPortPrivateData(q)
, descriptor(INVALID_HANDLE_VALUE)
, parityErrorOccurred(false)
, actualReadBufferSize(0)
, actualWriteBufferSize(0)
, acyncWritePosition(0)
, readyReadEmitted(0)
, writeSequenceStarted(false)
{
}
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
DWORD desiredAccess = 0;
DWORD originalEventMask = EV_ERR;
if (mode & QIODevice::ReadOnly) {
desiredAccess |= GENERIC_READ;
originalEventMask |= EV_RXCHAR;
}
if (mode & QIODevice::WriteOnly)
desiredAccess |= GENERIC_WRITE;
descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (descriptor == INVALID_HANDLE_VALUE) {
q_ptr->setError(decodeSystemError());
return false;
}
if (!::GetCommState(descriptor, &restoredDcb)) {
q_ptr->setError(decodeSystemError());
return false;
}
currentDcb = restoredDcb;
currentDcb.fBinary = TRUE;
currentDcb.fInX = FALSE;
currentDcb.fOutX = FALSE;
currentDcb.fAbortOnError = FALSE;
currentDcb.fNull = FALSE;
currentDcb.fErrorChar = FALSE;
if (!updateDcb())
return false;
if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) {
q_ptr->setError(decodeSystemError());
return false;
}
::memset(&currentCommTimeouts, 0, sizeof(currentCommTimeouts));
currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
if (!updateCommTimeouts())
return false;
if (originalEventMask & EV_RXCHAR) {
QWinEventNotifier *n = new ReadOverlappedCompletionNotifier(this, q_ptr);
n->setEnabled(true);
}
QWinEventNotifier *n = new CommOverlappedEventNotifier(this, originalEventMask, q_ptr);
n->setEnabled(true);
detectDefaultSettings();
return true;
}
void QSerialPortPrivate::close()
{
::CancelIo(descriptor);
qDeleteAll(notifiers);
notifiers.clear();
readBuffer.clear();
actualReadBufferSize = 0;
writeSequenceStarted = false;
writeBuffer.clear();
actualWriteBufferSize = 0;
acyncWritePosition = 0;
readyReadEmitted = false;
parityErrorOccurred = false;
if (settingsRestoredOnClose) {
::SetCommState(descriptor, &restoredDcb);
::SetCommTimeouts(descriptor, &restoredCommTimeouts);
}
::CloseHandle(descriptor);
descriptor = INVALID_HANDLE_VALUE;
}
#endif // #ifndef Q_OS_WINCE
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() const
{
DWORD modemStat = 0;
QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
if (!::GetCommModemStatus(descriptor, &modemStat)) {
q_ptr->setError(decodeSystemError());
return ret;
}
if (modemStat & MS_CTS_ON)
ret |= QSerialPort::ClearToSendSignal;
if (modemStat & MS_DSR_ON)
ret |= QSerialPort::DataSetReadySignal;
if (modemStat & MS_RING_ON)
ret |= QSerialPort::RingIndicatorSignal;
if (modemStat & MS_RLSD_ON)
ret |= QSerialPort::DataCarrierDetectSignal;
DWORD bytesReturned = 0;
if (::DeviceIoControl(descriptor, IOCTL_SERIAL_GET_DTRRTS, NULL, 0,
&modemStat, sizeof(modemStat),
&bytesReturned, NULL)) {
if (modemStat & SERIAL_DTR_STATE)
ret |= QSerialPort::DataTerminalReadySignal;
if (modemStat & SERIAL_RTS_STATE)
ret |= QSerialPort::RequestToSendSignal;
}
return ret;
}
bool QSerialPortPrivate::setDataTerminalReady(bool set)
{
return ::EscapeCommFunction(descriptor, set ? SETDTR : CLRDTR);
}
bool QSerialPortPrivate::setRequestToSend(bool set)
{
return ::EscapeCommFunction(descriptor, set ? SETRTS : CLRRTS);
}
#ifndef Q_OS_WINCE
bool QSerialPortPrivate::flush()
{
return startAsyncWrite() && ::FlushFileBuffers(descriptor);
}
bool QSerialPortPrivate::clear(QSerialPort::Directions dir)
{
DWORD flags = 0;
if (dir & QSerialPort::Input) {
flags |= PURGE_RXABORT | PURGE_RXCLEAR;
actualReadBufferSize = 0;
}
if (dir & QSerialPort::Output) {
flags |= PURGE_TXABORT | PURGE_TXCLEAR;
actualWriteBufferSize = 0;
acyncWritePosition = 0;
writeSequenceStarted = false;
}
return ::PurgeComm(descriptor, flags);
}
#endif
bool QSerialPortPrivate::sendBreak(int duration)
{
// FIXME:
if (setBreakEnabled(true)) {
::Sleep(duration);
if (setBreakEnabled(false))
return true;
}
return false;
}
bool QSerialPortPrivate::setBreakEnabled(bool set)
{
if (set)
return ::SetCommBreak(descriptor);
return ::ClearCommBreak(descriptor);
}
qint64 QSerialPortPrivate::systemInputQueueSize () const
{
COMSTAT cs;
::memset(&cs, 0, sizeof(cs));
if (!::ClearCommError(descriptor, NULL, &cs))
return -1;
return cs.cbInQue;
}
qint64 QSerialPortPrivate::systemOutputQueueSize () const
{
COMSTAT cs;
::memset(&cs, 0, sizeof(cs));
if (!::ClearCommError(descriptor, NULL, &cs))
return -1;
return cs.cbOutQue;
}
#ifndef Q_OS_WINCE
qint64 QSerialPortPrivate::bytesAvailable() const
{
return actualReadBufferSize;
}
qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
{
if (actualReadBufferSize == 0)
return 0;
qint64 readSoFar = -1;
if (maxSize == 1 && actualReadBufferSize > 0) {
*data = readBuffer.getChar();
actualReadBufferSize--;
readSoFar = 1;
} else {
const qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxSize);
readSoFar = 0;
while (readSoFar < bytesToRead) {
const char *ptr = readBuffer.readPointer();
const int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
qint64(readBuffer.nextDataBlockSize()));
::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
readBuffer.free(bytesToReadFromThisBlock);
actualReadBufferSize -= bytesToReadFromThisBlock;
}
}
return readSoFar;
}
qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
{
char *ptr = writeBuffer.reserve(maxSize);
if (maxSize == 1) {
*ptr = *data;
actualWriteBufferSize++;
} else {
::memcpy(ptr, data, maxSize);
actualWriteBufferSize += maxSize;
}
if (!writeSequenceStarted)
startAsyncWrite(WriteChunkSize);
return maxSize;
}
bool QSerialPortPrivate::waitForReadyRead(int msecs)
{
QElapsedTimer stopWatch;
stopWatch.start();
do {
bool timedOut = false;
AbstractOverlappedEventNotifier *n = 0;
if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) {
// This is occur timeout or another error
q_ptr->setError(decodeSystemError());
return false;
}
switch (n->type()) {
case AbstractOverlappedEventNotifier::CommEvent:
if (!n->processCompletionRoutine())
return false;
break;
case AbstractOverlappedEventNotifier::ReadCompletionEvent:
return n->processCompletionRoutine();
case AbstractOverlappedEventNotifier::WriteCompletionEvent:
n->processCompletionRoutine();
break;
default: // newer called
return false;
}
} while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0);
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msecs)
{
if (writeBuffer.isEmpty())
return false;
QElapsedTimer stopWatch;
stopWatch.start();
forever {
bool timedOut = false;
AbstractOverlappedEventNotifier *n = 0;
if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &n) || !n) {
q_ptr->setError(decodeSystemError());
return false;
}
switch (n->type()) {
case AbstractOverlappedEventNotifier::CommEvent:
// do nothing, jump to ReadCompletionEvent case
case AbstractOverlappedEventNotifier::ReadCompletionEvent:
n->processCompletionRoutine();
break;
case AbstractOverlappedEventNotifier::WriteCompletionEvent:
return n->processCompletionRoutine();
default: // newer called
return false;
}
}
return false;
}
#endif // #ifndef Q_OS_WINCE
bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions dir)
{
if (dir != QSerialPort::AllDirections) {
q_ptr->setError(QSerialPort::UnsupportedOperationError);
return false;
}
currentDcb.BaudRate = baudRate;
return updateDcb();
}
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
currentDcb.ByteSize = dataBits;
return updateDcb();
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
currentDcb.fParity = TRUE;
switch (parity) {
case QSerialPort::NoParity:
currentDcb.Parity = NOPARITY;
currentDcb.fParity = FALSE;
break;
case QSerialPort::OddParity:
currentDcb.Parity = ODDPARITY;
break;
case QSerialPort::EvenParity:
currentDcb.Parity = EVENPARITY;
break;
case QSerialPort::MarkParity:
currentDcb.Parity = MARKPARITY;
break;
case QSerialPort::SpaceParity:
currentDcb.Parity = SPACEPARITY;
break;
default:
currentDcb.Parity = NOPARITY;
currentDcb.fParity = FALSE;
break;
}
return updateDcb();
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
switch (stopBits) {
case QSerialPort::OneStop:
currentDcb.StopBits = ONESTOPBIT;
break;
case QSerialPort::OneAndHalfStop:
currentDcb.StopBits = ONE5STOPBITS;
break;
case QSerialPort::TwoStop:
currentDcb.StopBits = TWOSTOPBITS;
break;
default:
currentDcb.StopBits = ONESTOPBIT;
break;
}
return updateDcb();
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flow)
{
currentDcb.fInX = FALSE;
currentDcb.fOutX = FALSE;
currentDcb.fOutxCtsFlow = FALSE;
currentDcb.fRtsControl = RTS_CONTROL_DISABLE;
switch (flow) {
case QSerialPort::NoFlowControl:
break;
case QSerialPort::SoftwareControl:
currentDcb.fInX = TRUE;
currentDcb.fOutX = TRUE;
break;
case QSerialPort::HardwareControl:
currentDcb.fOutxCtsFlow = TRUE;
currentDcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
default:
break;
}
return updateDcb();
}
bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
{
policy = policy;
return true;
}
#ifndef Q_OS_WINCE
bool QSerialPortPrivate::startAsyncRead()
{
DWORD bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1;
if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
bytesToRead = readBufferMaxSize - readBuffer.size();
if (bytesToRead == 0) {
// Buffer is full. User must read data from the buffer
// before we can read more from the port.
return false;
}
}
AbstractOverlappedEventNotifier *n = lookupReadCompletionNotifier();
if (!n) {
q_ptr->setError(QSerialPort::ResourceError);
return false;
}
char *ptr = readBuffer.reserve(bytesToRead);
if (::ReadFile(descriptor, ptr, bytesToRead, NULL, n->overlappedPointer()))
return true;
QSerialPort::SerialPortError error = decodeSystemError();
if (error != QSerialPort::NoError) {
if (error != QSerialPort::ResourceError)
error = QSerialPort::ReadError;
q_ptr->setError(error);
readBuffer.truncate(actualReadBufferSize);
return false;
}
return true;
}
bool QSerialPortPrivate::startAsyncWrite(int maxSize)
{
qint64 nextSize = 0;
const char *ptr = writeBuffer.readPointerAtPosition(acyncWritePosition, nextSize);
nextSize = qMin(nextSize, qint64(maxSize));
acyncWritePosition += nextSize;
// no more data to write
if (!ptr || nextSize == 0)
return true;
writeSequenceStarted = true;
AbstractOverlappedEventNotifier *n = lookupFreeWriteCompletionNotifier();
if (!n) {
q_ptr->setError(QSerialPort::ResourceError);
return false;
}
n->setEnabled(true);
if (::WriteFile(descriptor, ptr, nextSize, NULL, n->overlappedPointer()))
return true;
QSerialPort::SerialPortError error = decodeSystemError();
if (error != QSerialPort::NoError) {
writeSequenceStarted = false;
if (error != QSerialPort::ResourceError)
error = QSerialPort::WriteError;
q_ptr->setError(error);
return false;
}
return true;
}
#endif // #ifndef Q_OS_WINCE
bool QSerialPortPrivate::processIoErrors(bool error)
{
if (error) {
q_ptr->setError(QSerialPort::ResourceError);
return true;
}
DWORD errors = 0;
const bool ret = ::ClearCommError(descriptor, &errors, NULL);
if (ret && errors) {
if (errors & CE_FRAME) {
q_ptr->setError(QSerialPort::FramingError);
} else if (errors & CE_RXPARITY) {
q_ptr->setError(QSerialPort::ParityError);
parityErrorOccurred = true;
} else if (errors & CE_BREAK) {
q_ptr->setError(QSerialPort::BreakConditionError);
} else {
q_ptr->setError(QSerialPort::UnknownError);
}
}
return ret;
}
#ifndef Q_OS_WINCE
bool QSerialPortPrivate::completeAsyncRead(DWORD numberOfBytes)
{
actualReadBufferSize += qint64(numberOfBytes);
readBuffer.truncate(actualReadBufferSize);
if (numberOfBytes > 0) {
// Process emulate policy.
if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) {
parityErrorOccurred = false;
// Ignore received character, remove it from buffer
if (policy == QSerialPort::SkipPolicy) {
readBuffer.getChar();
// Force returning without emitting a readyRead() signal
return true;
}
// Abort receiving
if (policy == QSerialPort::StopReceivingPolicy) {
readyReadEmitted = true;
emit q_ptr->readyRead();
return true;
}
// Replace received character by zero
if (policy == QSerialPort::PassZeroPolicy) {
readBuffer.getChar();
readBuffer.putChar('\0');
}
}
readyReadEmitted = true;
emit q_ptr->readyRead();
}
return true;
}
bool QSerialPortPrivate::completeAsyncWrite(DWORD numberOfBytes)
{
writeBuffer.free(numberOfBytes);
actualWriteBufferSize -= qint64(numberOfBytes);
acyncWritePosition -= qint64(numberOfBytes);
if (numberOfBytes > 0)
emit q_ptr->bytesWritten(numberOfBytes);
if (writeBuffer.isEmpty())
writeSequenceStarted = false;
else
startAsyncWrite(WriteChunkSize);
return true;
}
AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupFreeWriteCompletionNotifier()
{
// find first free not running write notifier
foreach (AbstractOverlappedEventNotifier *n, notifiers) {
if ((n->type() == AbstractOverlappedEventNotifier::WriteCompletionEvent)
&& !n->isEnabled()) {
return n;
}
}
// if all write notifiers in use, then create new write notifier
return new WriteOverlappedCompletionNotifier(this, q_ptr);
}
AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupCommEventNotifier()
{
foreach (AbstractOverlappedEventNotifier *n, notifiers) {
if (n->type() == AbstractOverlappedEventNotifier::CommEvent)
return n;
}
return 0;
}
AbstractOverlappedEventNotifier *QSerialPortPrivate::lookupReadCompletionNotifier()
{
foreach (AbstractOverlappedEventNotifier *n, notifiers) {
if (n->type() == AbstractOverlappedEventNotifier::ReadCompletionEvent)
return n;
}
return 0;
}
bool QSerialPortPrivate::updateDcb()
{
if (!::SetCommState(descriptor, &currentDcb)) {
q_ptr->setError(decodeSystemError());
return false;
}
return true;
}
bool QSerialPortPrivate::updateCommTimeouts()
{
if (!::SetCommTimeouts(descriptor, &currentCommTimeouts)) {
q_ptr->setError(decodeSystemError());
return false;
}
return true;
}
#endif // #ifndef Q_OS_WINCE
void QSerialPortPrivate::detectDefaultSettings()
{
// Detect baud rate.
inputBaudRate = quint32(currentDcb.BaudRate);
outputBaudRate = inputBaudRate;
// Detect databits.
switch (currentDcb.ByteSize) {
case 5:
dataBits = QSerialPort::Data5;
break;
case 6:
dataBits = QSerialPort::Data6;
break;
case 7:
dataBits = QSerialPort::Data7;
break;
case 8:
dataBits = QSerialPort::Data8;
break;
default:
dataBits = QSerialPort::UnknownDataBits;
break;
}
// Detect parity.
if ((currentDcb.Parity == NOPARITY) && !currentDcb.fParity)
parity = QSerialPort::NoParity;
else if ((currentDcb.Parity == SPACEPARITY) && currentDcb.fParity)
parity = QSerialPort::SpaceParity;
else if ((currentDcb.Parity == MARKPARITY) && currentDcb.fParity)
parity = QSerialPort::MarkParity;
else if ((currentDcb.Parity == EVENPARITY) && currentDcb.fParity)
parity = QSerialPort::EvenParity;
else if ((currentDcb.Parity == ODDPARITY) && currentDcb.fParity)
parity = QSerialPort::OddParity;
else
parity = QSerialPort::UnknownParity;
// Detect stopbits.
switch (currentDcb.StopBits) {
case ONESTOPBIT:
stopBits = QSerialPort::OneStop;
break;
case ONE5STOPBITS:
stopBits = QSerialPort::OneAndHalfStop;
break;
case TWOSTOPBITS:
stopBits = QSerialPort::TwoStop;
break;
default:
stopBits = QSerialPort::UnknownStopBits;
break;
}
// Detect flow control.
if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE)
&& !currentDcb.fInX && !currentDcb.fOutX) {
flow = QSerialPort::NoFlowControl;
} else if (!currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_DISABLE)
&& currentDcb.fInX && currentDcb.fOutX) {
flow = QSerialPort::SoftwareControl;
} else if (currentDcb.fOutxCtsFlow && (currentDcb.fRtsControl == RTS_CONTROL_HANDSHAKE)
&& !currentDcb.fInX && !currentDcb.fOutX) {
flow = QSerialPort::HardwareControl;
} else
flow = QSerialPort::UnknownFlowControl;
}
QSerialPort::SerialPortError QSerialPortPrivate::decodeSystemError() const
{
QSerialPort::SerialPortError error;
switch (::GetLastError()) {
case ERROR_IO_PENDING:
error = QSerialPort::NoError;
break;
case ERROR_MORE_DATA:
error = QSerialPort::NoError;
break;
case ERROR_FILE_NOT_FOUND:
error = QSerialPort::DeviceNotFoundError;
break;
case ERROR_ACCESS_DENIED:
error = QSerialPort::PermissionError;
break;
case ERROR_INVALID_HANDLE:
error = QSerialPort::ResourceError;
break;
case ERROR_INVALID_PARAMETER:
error = QSerialPort::UnsupportedOperationError;
break;
case ERROR_BAD_COMMAND:
error = QSerialPort::ResourceError;
break;
case ERROR_DEVICE_REMOVED:
error = QSerialPort::ResourceError;
break;
default:
error = QSerialPort::UnknownError;
break;
}
return error;
}
#ifndef Q_OS_WINCE
bool QSerialPortPrivate::waitAnyEvent(int msecs, bool *timedOut,
AbstractOverlappedEventNotifier **triggeredNotifier)
{
Q_ASSERT(timedOut);
QVector<HANDLE> handles = notifiers.keys().toVector();
DWORD waitResult = ::WaitForMultipleObjects(handles.count(),
handles.constData(),
FALSE, // wait any event
qMax(msecs, 0));
if (waitResult == WAIT_TIMEOUT) {
*timedOut = true;
return false;
}
if (int(waitResult) > (handles.count() - 1))
return false;
HANDLE h = handles.at(waitResult - WAIT_OBJECT_0);
*triggeredNotifier = notifiers.value(h);
return true;
}
static const QLatin1String defaultPathPrefix("\\\\.\\");
QString QSerialPortPrivate::portNameToSystemLocation(const QString &port)
{
QString ret = port;
if (!ret.contains(defaultPathPrefix))
ret.prepend(defaultPathPrefix);
return ret;
}
QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location)
{
QString ret = location;
if (ret.contains(defaultPathPrefix))
ret.remove(defaultPathPrefix);
return ret;
}
#endif // #ifndef Q_OS_WINCE
// This table contains standard values of baud rates that
// are defined in MSDN and/or in Win SDK file winbase.h
static const QList<qint32> standardBaudRatePairList()
{
static const QList<qint32> standardBaudRatesTable = QList<qint32>()
#ifdef CBR_110
<< CBR_110
#endif
#ifdef CBR_300
<< CBR_300
#endif
#ifdef CBR_600
<< CBR_600
#endif
#ifdef CBR_1200
<< CBR_1200
#endif
#ifdef CBR_2400
<< CBR_2400
#endif
#ifdef CBR_4800
<< CBR_4800
#endif
#ifdef CBR_9600
<< CBR_9600
#endif
#ifdef CBR_14400
<< CBR_14400
#endif
#ifdef CBR_19200
<< CBR_19200
#endif
#ifdef CBR_38400
<< CBR_38400
#endif
#ifdef CBR_56000
<< CBR_56000
#endif
#ifdef CBR_57600
<< CBR_57600
#endif
#ifdef CBR_115200
<< CBR_115200
#endif
#ifdef CBR_128000
<< CBR_128000
#endif
#ifdef CBR_256000
<< CBR_256000
#endif
;
return standardBaudRatesTable;
};
qint32 QSerialPortPrivate::baudRateFromSetting(qint32 setting)
{
const QList<qint32> baudRatePairs = standardBaudRatePairList();
const QList<qint32>::const_iterator baudRatePairListConstIterator = qFind(baudRatePairs, setting);
return (baudRatePairListConstIterator != baudRatePairs.constEnd()) ? *baudRatePairListConstIterator : 0;
}
qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
{
const QList<qint32> baudRatePairList = standardBaudRatePairList();
const QList<qint32>::const_iterator baudRatePairListConstIterator = qFind(baudRatePairList, baudRate);
return (baudRatePairListConstIterator != baudRatePairList.constEnd()) ? *baudRatePairListConstIterator : 0;
}
QList<qint32> QSerialPortPrivate::standardBaudRates()
{
QList<qint32> ret;
const QList<qint32> baudRatePairs = standardBaudRatePairList();
foreach (qint32 baudRatePair, baudRatePairs) {
ret.append(baudRatePair);
}
return ret;
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORT_WIN_P_H
#define QSERIALPORT_WIN_P_H
#include "qserialport_p.h"
#include <qt_windows.h>
#ifndef Q_OS_WINCE
#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
class QWinEventNotifier;
#else
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
class QThread;
#endif
#ifndef Q_OS_WINCE
class AbstractOverlappedEventNotifier;
#endif
class QSerialPortPrivate : public QSerialPortPrivateData
{
public:
QSerialPortPrivate(QSerialPort *q);
bool open(QIODevice::OpenMode mode);
void close();
QSerialPort::PinoutSignals pinoutSignals() const;
bool setDataTerminalReady(bool set);
bool setRequestToSend(bool set);
bool flush();
bool clear(QSerialPort::Directions dir);
bool sendBreak(int duration);
bool setBreakEnabled(bool set);
qint64 systemInputQueueSize () const;
qint64 systemOutputQueueSize () const;
qint64 bytesAvailable() const;
qint64 readFromBuffer(char *data, qint64 maxSize);
qint64 writeToBuffer(const char *data, qint64 maxSize);
bool waitForReadyRead(int msec);
bool waitForBytesWritten(int msec);
bool setBaudRate(qint32 baudRate, QSerialPort::Directions dir);
bool setDataBits(QSerialPort::DataBits dataBits);
bool setParity(QSerialPort::Parity parity);
bool setStopBits(QSerialPort::StopBits stopBits);
bool setFlowControl(QSerialPort::FlowControl flowControl);
bool setDataErrorPolicy(QSerialPort::DataErrorPolicy policy);
bool processIoErrors(bool error);
#ifndef Q_OS_WINCE
bool startAsyncRead();
bool startAsyncWrite(int maxSize = INT_MAX);
bool completeAsyncRead(DWORD numberOfBytes);
bool completeAsyncWrite(DWORD numberOfBytes);
AbstractOverlappedEventNotifier *lookupFreeWriteCompletionNotifier();
AbstractOverlappedEventNotifier *lookupCommEventNotifier();
AbstractOverlappedEventNotifier *lookupReadCompletionNotifier();
#else
bool notifyRead();
bool notifyWrite(int maxSize = INT_MAX);
#endif
static QString portNameToSystemLocation(const QString &port);
static QString portNameFromSystemLocation(const QString &location);
static qint32 baudRateFromSetting(qint32 setting);
static qint32 settingFromBaudRate(qint32 baudRate);
static QList<qint32> standardBaudRates();
DCB currentDcb;
DCB restoredDcb;
COMMTIMEOUTS currentCommTimeouts;
COMMTIMEOUTS restoredCommTimeouts;
HANDLE descriptor;
bool parityErrorOccurred;
#ifndef Q_OS_WINCE
QHash<HANDLE, AbstractOverlappedEventNotifier *> notifiers;
qint64 actualReadBufferSize;
qint64 actualWriteBufferSize;
qint64 acyncWritePosition;
bool readyReadEmitted;
bool writeSequenceStarted;
#else
QThread *eventNotifier;
QMutex settingsChangeMutex;
#endif
private:
bool updateDcb();
bool updateCommTimeouts();
void detectDefaultSettings();
QSerialPort::SerialPortError decodeSystemError() const;
#ifndef Q_OS_WINCE
bool waitAnyEvent(int msecs, bool *timedOut,
AbstractOverlappedEventNotifier **triggeredNotifier);
#else
bool waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut);
#endif
};
QT_END_NAMESPACE
#endif // QSERIALPORT_WIN_P_H
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialport_win_p.h"
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qthread.h>
#include <QtCore/qtimer.h>
QT_BEGIN_NAMESPACE
class QSerialPortPrivate;
class CommEventNotifier : public QThread
{
Q_OBJECT
signals:
void eventMask(quint32 mask);
public:
CommEventNotifier(DWORD mask, QSerialPortPrivate *d, QObject *parent)
: QThread(parent), dptr(d), running(true) {
connect(this, SIGNAL(eventMask(quint32)), this, SLOT(processNotification(quint32)));
::SetCommMask(dptr->descriptor, mask);
}
virtual ~CommEventNotifier() {
running = false;
::SetCommMask(dptr->descriptor, 0);
wait();
}
protected:
void run() Q_DECL_OVERRIDE {
DWORD mask = 0;
while (running) {
if (::WaitCommEvent(dptr->descriptor, &mask, FALSE)) {
// Wait until complete the operation changes the port settings,
// see updateDcb().
dptr->settingsChangeMutex.lock();
dptr->settingsChangeMutex.unlock();
emit eventMask(quint32(mask));
}
}
}
private slots:
void processNotification(quint32 eventMask) {
bool error = false;
// Check for unexpected event. This event triggered when pulled previously
// opened device from the system, when opened as for not to read and not to
// write options and so forth.
if ((eventMask == 0)
|| ((eventMask & (EV_ERR | EV_RXCHAR | EV_TXEMPTY)) == 0)) {
error = true;
}
if (error || (EV_ERR & eventMask))
dptr->processIoErrors(error);
if (EV_RXCHAR & eventMask)
dptr->notifyRead();
if (EV_TXEMPTY & eventMask)
dptr->notifyWrite(QSerialPortPrivateData::WriteChunkSize);
}
private:
QSerialPortPrivate *dptr;
mutable bool running;
};
class WaitCommEventBreaker : public QThread
{
Q_OBJECT
public:
WaitCommEventBreaker(HANDLE descriptor, int timeout, QObject *parent = 0)
: QThread(parent), descriptor(descriptor), timeout(timeout), worked(false) {
start();
}
virtual ~WaitCommEventBreaker() {
stop();
wait();
}
void stop() {
exit(0);
}
bool isWorked() const {
return worked;
}
protected:
void run() {
QTimer timer;
QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(processTimeout()), Qt::DirectConnection);
timer.start(timeout);
exec();
worked = true;
}
private slots:
void processTimeout() {
::SetCommMask(descriptor, 0);
stop();
}
private:
HANDLE descriptor;
int timeout;
mutable bool worked;
};
QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q)
: QSerialPortPrivateData(q)
, descriptor(INVALID_HANDLE_VALUE)
, parityErrorOccurred(false)
, eventNotifier(0)
{
}
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
DWORD desiredAccess = 0;
DWORD eventMask = EV_ERR;
if (mode & QIODevice::ReadOnly) {
desiredAccess |= GENERIC_READ;
eventMask |= EV_RXCHAR;
}
if (mode & QIODevice::WriteOnly) {
desiredAccess |= GENERIC_WRITE;
eventMask |= EV_TXEMPTY;
}
descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
desiredAccess, 0, NULL, OPEN_EXISTING, 0, NULL);
if (descriptor == INVALID_HANDLE_VALUE) {
q_ptr->setError(decodeSystemError());
return false;
}
if (!::GetCommState(descriptor, &restoredDcb)) {
q_ptr->setError(decodeSystemError());
return false;
}
currentDcb = restoredDcb;
currentDcb.fBinary = true;
currentDcb.fInX = false;
currentDcb.fOutX = false;
currentDcb.fAbortOnError = false;
currentDcb.fNull = false;
currentDcb.fErrorChar = false;
if (!updateDcb())
return false;
if (!::GetCommTimeouts(descriptor, &restoredCommTimeouts)) {
q_ptr->setError(decodeSystemError());
return false;
}
::memset(&currentCommTimeouts, 0, sizeof(currentCommTimeouts));
currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
if (!updateCommTimeouts())
return false;
eventNotifier = new CommEventNotifier(eventMask, this, q_ptr);
eventNotifier->start();
detectDefaultSettings();
return true;
}
void QSerialPortPrivate::close()
{
if (eventNotifier) {
eventNotifier->deleteLater();
eventNotifier = 0;
}
if (settingsRestoredOnClose) {
::SetCommState(descriptor, &restoredDcb);
::SetCommTimeouts(descriptor, &restoredCommTimeouts);
}
::CloseHandle(descriptor);
descriptor = INVALID_HANDLE_VALUE;
}
bool QSerialPortPrivate::flush()
{
return notifyWrite() && ::FlushFileBuffers(descriptor);
}
bool QSerialPortPrivate::clear(QSerialPort::Directions dir)
{
DWORD flags = 0;
if (dir & QSerialPort::Input)
flags |= PURGE_RXABORT | PURGE_RXCLEAR;
if (dir & QSerialPort::Output)
flags |= PURGE_TXABORT | PURGE_TXCLEAR;
return ::PurgeComm(descriptor, flags);
}
qint64 QSerialPortPrivate::bytesAvailable() const
{
return readBuffer.size();
}
qint64 QSerialPortPrivate::readFromBuffer(char *data, qint64 maxSize)
{
if (readBuffer.isEmpty())
return 0;
if (maxSize == 1) {
*data = readBuffer.getChar();
return 1;
}
const qint64 bytesToRead = qMin(qint64(readBuffer.size()), maxSize);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
const char *ptr = readBuffer.readPointer();
const int bytesToReadFromThisBlock = qMin(int(bytesToRead - readSoFar),
readBuffer.nextDataBlockSize());
::memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
readBuffer.free(bytesToReadFromThisBlock);
}
return readSoFar;
}
qint64 QSerialPortPrivate::writeToBuffer(const char *data, qint64 maxSize)
{
char *ptr = writeBuffer.reserve(maxSize);
if (maxSize == 1)
*ptr = *data;
else
::memcpy(ptr, data, maxSize);
// trigger write sequence
notifyWrite(QSerialPortPrivateData::WriteChunkSize);
return maxSize;
}
bool QSerialPortPrivate::waitForReadyRead(int msec)
{
if (!readBuffer.isEmpty())
return true;
QElapsedTimer stopWatch;
stopWatch.start();
forever {
bool readyToRead = false;
bool readyToWrite = false;
bool timedOut = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite,
true, !writeBuffer.isEmpty(),
timeoutValue(msec, stopWatch.elapsed()),
&timedOut)) {
return false;
}
if (readyToRead) {
if (notifyRead())
return true;
}
if (readyToWrite)
notifyWrite(WriteChunkSize);
}
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msec)
{
if (writeBuffer.isEmpty())
return false;
QElapsedTimer stopWatch;
stopWatch.start();
forever {
bool readyToRead = false;
bool readyToWrite = false;
bool timedOut = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite,
true, !writeBuffer.isEmpty(),
timeoutValue(msec, stopWatch.elapsed()),
&timedOut)) {
return false;
}
if (readyToRead) {
if (!notifyRead())
return false;
}
if (readyToWrite) {
if (notifyWrite(WriteChunkSize))
return true;
}
}
return false;
}
bool QSerialPortPrivate::notifyRead()
{
DWORD bytesToRead = (policy == QSerialPort::IgnorePolicy) ? ReadChunkSize : 1;
if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) {
bytesToRead = readBufferMaxSize - readBuffer.size();
if (bytesToRead == 0) {
// Buffer is full. User must read data from the buffer
// before we can read more from the port.
return false;
}
}
char *ptr = readBuffer.reserve(bytesToRead);
DWORD readBytes = 0;
BOOL sucessResult = ::ReadFile(descriptor, ptr, bytesToRead, &readBytes, NULL);
if (!sucessResult) {
readBuffer.truncate(bytesToRead);
q_ptr->setError(QSerialPort::ReadError);
return false;
}
readBuffer.truncate(readBytes);
// Process emulate policy.
if ((policy != QSerialPort::IgnorePolicy) && parityErrorOccurred) {
parityErrorOccurred = false;
switch (policy) {
case QSerialPort::SkipPolicy:
readBuffer.getChar();
return true;
case QSerialPort::PassZeroPolicy:
readBuffer.getChar();
readBuffer.putChar('\0');
break;
case QSerialPort::StopReceivingPolicy:
// FIXME: Maybe need disable read notifier?
break;
default:
break;
}
}
if (readBytes > 0)
emit q_ptr->readyRead();
return true;
}
bool QSerialPortPrivate::notifyWrite(int maxSize)
{
int nextSize = qMin(writeBuffer.nextDataBlockSize(), maxSize);
const char *ptr = writeBuffer.readPointer();
DWORD bytesWritten = 0;
if (!::WriteFile(descriptor, ptr, nextSize, &bytesWritten, NULL)) {
q_ptr->setError(QSerialPort::WriteError);
return false;
}
writeBuffer.free(bytesWritten);
if (bytesWritten > 0)
emit q_ptr->bytesWritten(bytesWritten);
return true;
}
bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs, bool *timedOut)
{
DWORD eventMask = 0;
// FIXME: Here the situation is not properly handled with zero timeout:
// breaker can work out before you call a method WaitCommEvent()
// and so it will loop forever!
WaitCommEventBreaker breaker(descriptor, qMax(msecs, 0));
::WaitCommEvent(descriptor, &eventMask, NULL);
breaker.stop();
if (breaker.isWorked())
*timedOut = true;
if (!breaker.isWorked()) {
if (checkRead) {
Q_ASSERT(selectForRead);
*selectForRead = eventMask & EV_RXCHAR;
}
if (checkWrite) {
Q_ASSERT(selectForWrite);
*selectForWrite = eventMask & EV_TXEMPTY;
}
return true;
}
return false;
}
bool QSerialPortPrivate::updateDcb()
{
QMutexLocker locker(&settingsChangeMutex);
DWORD eventMask = 0;
// Save the event mask
if (!::GetCommMask(descriptor, &eventMask))
return false;
// Break event notifier from WaitCommEvent
::SetCommMask(descriptor, 0);
// Change parameters
bool ret = ::SetCommState(descriptor, &currentDcb);
if (!ret)
q_ptr->setError(decodeSystemError());
// Restore the event mask
::SetCommMask(descriptor, eventMask);
return ret;
}
bool QSerialPortPrivate::updateCommTimeouts()
{
if (!::SetCommTimeouts(descriptor, &currentCommTimeouts)) {
q_ptr->setError(decodeSystemError());
return false;
}
return true;
}
static const QLatin1String defaultPathPostfix(":");
QString QSerialPortPrivate::portNameToSystemLocation(const QString &port)
{
QString ret = port;
if (!ret.contains(defaultPathPostfix))
ret.append(defaultPathPostfix);
return ret;
}
QString QSerialPortPrivate::portNameFromSystemLocation(const QString &location)
{
QString ret = location;
if (ret.contains(defaultPathPostfix))
ret.remove(defaultPathPostfix);
return ret;
}
#include "qserialport_wince.moc"
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORTGLOBAL_H
#define QSERIALPORTGLOBAL_H
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
#ifndef QT_STATIC
# if defined(QT_BUILD_SERIALPORT_LIB)
# define Q_SERIALPORT_EXPORT Q_DECL_EXPORT
# else
# define Q_SERIALPORT_EXPORT Q_DECL_IMPORT
# endif
#else
# define Q_SERIALPORT_EXPORT
#endif
// The macro has been available only since Qt 5.0
#ifndef Q_DECL_OVERRIDE
#define Q_DECL_OVERRIDE
#endif
QT_END_NAMESPACE
#endif // QSERIALPORTGLOBAL_H
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include "qserialport.h"
QT_BEGIN_NAMESPACE
/*!
\class QSerialPortInfo
\brief Provides information about existing serial ports.
\ingroup serialport-main
\inmodule QtSerialPort
\since 5.1
Use the static functions to generate a list of QSerialPortInfo
objects. Each QSerialPortInfo object in the list represents a single
serial port and can be queried for the port name, system location,
description, and manufacturer. The QSerialPortInfo class can also be
used as an input parameter for the setPort() method of the QSerialPort
class.
\sa QSerialPort
*/
/*!
Constructs an empty QSerialPortInfo object.
\sa isNull()
*/
QSerialPortInfo::QSerialPortInfo()
: d_ptr(new QSerialPortInfoPrivate)
{
}
/*!
Constructs a copy of \a other.
*/
QSerialPortInfo::QSerialPortInfo(const QSerialPortInfo &other)
: d_ptr(other.d_ptr ? new QSerialPortInfoPrivate(*other.d_ptr) : 0)
{
}
/*!
Constructs a QSerialPortInfo object from serial \a port.
*/
QSerialPortInfo::QSerialPortInfo(const QSerialPort &port)
: d_ptr(new QSerialPortInfoPrivate)
{
foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) {
if (port.portName() == serialPortInfo.portName()) {
*this = serialPortInfo;
break;
}
}
}
/*!
Constructs a QSerialPortInfo object from serial port \a name.
This constructor finds the relevant serial port among the available ones
according to the port name \a name, and constructs the serial port info
instance for that port.
*/
QSerialPortInfo::QSerialPortInfo(const QString &name)
: d_ptr(new QSerialPortInfoPrivate)
{
foreach (const QSerialPortInfo &serialPortInfo, availablePorts()) {
if (name == serialPortInfo.portName()) {
*this = serialPortInfo;
break;
}
}
}
/*!
Destroys the QSerialPortInfo object. References to the values in the
object become invalid.
*/
QSerialPortInfo::~QSerialPortInfo()
{
}
/*! \fn void QSerialPortInfo::swap(QSerialPortInfo &other)
Swaps QSerialPortInfo \a other with this QSerialPortInfo. This operation is
very fast and never fails.
*/
void QSerialPortInfo::swap(QSerialPortInfo &other)
{
d_ptr.swap(other.d_ptr);
}
/*!
Sets the QSerialPortInfo object to be equal to \a other.
*/
QSerialPortInfo& QSerialPortInfo::operator=(const QSerialPortInfo &other)
{
QSerialPortInfo(other).swap(*this);
return *this;
}
/*!
Returns the name of the serial port.
*/
QString QSerialPortInfo::portName() const
{
Q_D(const QSerialPortInfo);
return !d ? QString() : d->portName;
}
/*!
Returns the system location of the serial port.
*/
QString QSerialPortInfo::systemLocation() const
{
Q_D(const QSerialPortInfo);
return !d ? QString() : d->device;
}
/*!
Returns the description string of the serial port,
if available; otherwise returns an empty string.
*/
QString QSerialPortInfo::description() const
{
Q_D(const QSerialPortInfo);
return !d ? QString() : d->description;
}
/*!
Returns the manufacturer string of the serial port,
if available; otherwise returns an empty string.
*/
QString QSerialPortInfo::manufacturer() const
{
Q_D(const QSerialPortInfo);
return !d ? QString() : d->manufacturer;
}
/*!
Returns the 16-bit vendor number for the serial port, if available;
otherwise returns zero.
*/
quint16 QSerialPortInfo::vendorIdentifier() const
{
Q_D(const QSerialPortInfo);
return !d ? 0 : d->vendorIdentifier;
}
/*!
Returns the 16-bit product number for the serial port, if available;
otherwise returns zero.
*/
quint16 QSerialPortInfo::productIdentifier() const
{
Q_D(const QSerialPortInfo);
return !d ? 0 : d->productIdentifier;
}
/*!
Returns true if there is a valid 16-bit vendor number present; otherwise
returns false.
*/
bool QSerialPortInfo::hasVendorIdentifier() const
{
Q_D(const QSerialPortInfo);
return !d ? false : d->hasVendorIdentifier;
}
/*!
Returns true if there is a valid 16-bit product number present; otherwise
returns false.
*/
bool QSerialPortInfo::hasProductIdentifier() const
{
Q_D(const QSerialPortInfo);
return !d ? false : d->hasProductIdentifier;
}
/*!
\fn bool QSerialPortInfo::isNull() const
Returns whether this QSerialPortInfo object holds a
serial port definition.
*/
/*!
\fn bool QSerialPortInfo::isBusy() const
Returns true if serial port is busy;
otherwise returns false.
*/
/*!
\fn bool QSerialPortInfo::isValid() const
Returns true if serial port is present on system;
otherwise returns false.
*/
/*!
\fn QList<qint32> QSerialPortInfo::standardBaudRates()
Returns a list of available standard baud rates supported by
the current serial port.
*/
/*!
\fn QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
Returns a list of available serial ports on the system.
*/
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORTINFO_H
#define QSERIALPORTINFO_H
#include <QtCore/qlist.h>
#include <QtCore/qscopedpointer.h>
#include <qserialportglobal.h>
//#include <QtSerialPort/qserialportglobal.h>
QT_BEGIN_NAMESPACE
class QSerialPort;
class QSerialPortInfoPrivate;
class QSerialPortInfoPrivateDeleter;
class Q_SERIALPORT_EXPORT QSerialPortInfo
{
Q_DECLARE_PRIVATE(QSerialPortInfo)
public:
QSerialPortInfo();
explicit QSerialPortInfo(const QSerialPort &port);
explicit QSerialPortInfo(const QString &name);
QSerialPortInfo(const QSerialPortInfo &other);
~QSerialPortInfo();
QSerialPortInfo& operator=(const QSerialPortInfo &other);
void swap(QSerialPortInfo &other);
QString portName() const;
QString systemLocation() const;
QString description() const;
QString manufacturer() const;
quint16 vendorIdentifier() const;
quint16 productIdentifier() const;
bool hasVendorIdentifier() const;
bool hasProductIdentifier() const;
bool isNull() const;
bool isBusy() const;
bool isValid() const;
static QList<qint32> standardBaudRates();
static QList<QSerialPortInfo> availablePorts();
private:
QScopedPointer<QSerialPortInfoPrivate, QSerialPortInfoPrivateDeleter> d_ptr;
};
inline bool QSerialPortInfo::isNull() const
{ return !d_ptr; }
QT_END_NAMESPACE
#endif // QSERIALPORTINFO_H
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include <sys/param.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h> // for kIOPropertyProductNameKey
#include <IOKit/usb/USB.h>
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
# include <IOKit/serial/ioss.h>
#endif
#include <IOKit/IOBSD.h>
QT_BEGIN_NAMESPACE
enum { MATCHING_PROPERTIES_COUNT = 6 };
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
QList<QSerialPortInfo> serialPortInfoList;
int matchingPropertiesCounter = 0;
::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue);
if (!matching)
return serialPortInfoList;
::CFDictionaryAddValue(matching,
CFSTR(kIOSerialBSDTypeKey),
CFSTR(kIOSerialBSDAllTypes));
io_iterator_t iter = 0;
kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault,
matching,
&iter);
if (kr != kIOReturnSuccess)
return serialPortInfoList;
io_registry_entry_t service;
while ((service = ::IOIteratorNext(iter))) {
::CFTypeRef device = 0;
::CFTypeRef portName = 0;
::CFTypeRef description = 0;
::CFTypeRef manufacturer = 0;
::CFTypeRef vendorIdentifier = 0;
::CFTypeRef productIdentifier = 0;
io_registry_entry_t entry = service;
// Find MacOSX-specific properties names.
do {
if (!device) {
device =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault,
0);
if (device)
++matchingPropertiesCounter;
}
if (!portName) {
portName =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kIOTTYDeviceKey),
kCFAllocatorDefault,
0);
if (portName)
++matchingPropertiesCounter;
}
if (!description) {
description =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kIOPropertyProductNameKey),
kCFAllocatorDefault,
0);
if (!description)
description =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kUSBProductString),
kCFAllocatorDefault,
0);
if (!description)
description =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR("BTName"),
kCFAllocatorDefault,
0);
if (description)
++matchingPropertiesCounter;
}
if (!manufacturer) {
manufacturer =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kUSBVendorString),
kCFAllocatorDefault,
0);
if (manufacturer)
++matchingPropertiesCounter;
}
if (!vendorIdentifier) {
vendorIdentifier =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kUSBVendorID),
kCFAllocatorDefault,
0);
if (vendorIdentifier)
++matchingPropertiesCounter;
}
if (!productIdentifier) {
productIdentifier =
::IORegistryEntrySearchCFProperty(entry,
kIOServicePlane,
CFSTR(kUSBProductID),
kCFAllocatorDefault,
0);
if (productIdentifier)
++matchingPropertiesCounter;
}
// If all matching properties is found, then force break loop.
if (matchingPropertiesCounter == MATCHING_PROPERTIES_COUNT)
break;
kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry);
} while (kr == kIOReturnSuccess);
(void) ::IOObjectRelease(entry);
// Convert from MacOSX-specific properties to Qt4-specific.
if (matchingPropertiesCounter > 0) {
QSerialPortInfo serialPortInfo;
QByteArray buffer(MAXPATHLEN, 0);
if (device) {
if (::CFStringGetCString(CFStringRef(device),
buffer.data(),
buffer.size(),
kCFStringEncodingUTF8)) {
serialPortInfo.d_ptr->device = QString::fromUtf8(buffer);
}
::CFRelease(device);
}
if (portName) {
if (::CFStringGetCString(CFStringRef(portName),
buffer.data(),
buffer.size(),
kCFStringEncodingUTF8)) {
serialPortInfo.d_ptr->portName = QString::fromUtf8(buffer);
}
::CFRelease(portName);
}
if (description) {
if (::CFStringGetCString(CFStringRef(description),
buffer.data(),
buffer.size(),
kCFStringEncodingUTF8)) {
serialPortInfo.d_ptr->description = QString::fromUtf8(buffer);
}
::CFRelease(description);
}
if (manufacturer) {
if (::CFStringGetCString(CFStringRef(manufacturer),
buffer.data(),
buffer.size(),
kCFStringEncodingUTF8)) {
serialPortInfo.d_ptr->manufacturer = QString::fromUtf8(buffer);
}
::CFRelease(manufacturer);
}
quint16 value = 0;
if (vendorIdentifier) {
serialPortInfo.d_ptr->hasVendorIdentifier = ::CFNumberGetValue(CFNumberRef(vendorIdentifier), kCFNumberIntType, &value);
if (serialPortInfo.d_ptr->hasVendorIdentifier)
serialPortInfo.d_ptr->vendorIdentifier = value;
::CFRelease(vendorIdentifier);
}
if (productIdentifier) {
serialPortInfo.d_ptr->hasProductIdentifier = ::CFNumberGetValue(CFNumberRef(productIdentifier), kCFNumberIntType, &value);
if (serialPortInfo.d_ptr->hasProductIdentifier)
serialPortInfo.d_ptr->productIdentifier = value;
::CFRelease(productIdentifier);
}
serialPortInfoList.append(serialPortInfo);
}
(void) ::IOObjectRelease(service);
}
(void) ::IOObjectRelease(iter);
return serialPortInfoList;
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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 QSERIALPORTINFO_P_H
#define QSERIALPORTINFO_P_H
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
class QSerialPortInfoPrivate
{
public:
QSerialPortInfoPrivate()
: vendorIdentifier(0)
, productIdentifier(0)
, hasVendorIdentifier(false)
, hasProductIdentifier(false)
{}
~QSerialPortInfoPrivate() {}
QString portName;
QString device;
QString description;
QString manufacturer;
quint16 vendorIdentifier;
quint16 productIdentifier;
bool hasVendorIdentifier;
bool hasProductIdentifier;
};
class QSerialPortInfoPrivateDeleter
{
public:
static void cleanup(QSerialPortInfoPrivate *p) {
delete p;
}
};
QT_END_NAMESPACE
#endif // QSERIALPORTINFO_P_H
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include "qserialport_symbian_p.h"
#include <e32base.h>
//#include <e32test.h>
#include <c32comm.h>
#include <f32file.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
// Physical device driver.
#ifdef __WINS__
_LIT(KPddName, "ECDRV");
#else // defined (__EPOC32__)
_LIT(KPddName, "EUART");
#endif
// Logical native device driver.
_LIT(KLddName,"ECOMM");
// Modules names.
_LIT(KRS232ModuleName , "ECUART");
_LIT(KBluetoothModuleName , "BTCOMM");
_LIT(KInfraRedModuleName , "IRCOMM");
_LIT(KACMModuleName, "ECACM");
// Return false on error load.
static bool loadDevices()
{
TInt r = KErrNone;
#ifdef __WINS__
RFs fileServer;
r = User::LeaveIfError(fileServer.Connect());
if (r != KErrNone)
return false;
fileServer.Close ();
#endif
r = User::LoadPhysicalDevice(KPddName);
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
r = User::LoadLogicalDevice(KLddName);
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
#ifndef __WINS__
r = StartC32();
if (r != KErrNone && r != KErrAlreadyExists)
return false; //User::Leave(r);
#endif
return true;
}
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
QList<QSerialPortInfo> serialPortInfoList;
if (!loadDevices())
return serialPortInfoList;
RCommServ server;
TInt r = server.Connect();
if (r != KErrNone)
return serialPortInfoList; //User::LeaveIfError(r);
TSerialInfo nativeSerialInfo; // Native Symbian OS port info class.
QString s("%1::%2");
// FIXME: Get info about RS232 ports.
r = server.LoadCommModule(KRS232ModuleName);
//User::LeaveIfError(r);
if (r == KErrNone) {
r = server.GetPortInfo(KRS232ModuleName, nativeSerialInfo);
if (r == KErrNone) {
for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = s
.arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length()))
.arg(i);
serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device;
serialPortInfo.d_ptr->description =
QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length());
serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
serialPortInfoList.append(serialPortInfo);
}
}
}
// FIXME: Get info about Bluetooth ports.
r = server.LoadCommModule(KBluetoothModuleName);
//User::LeaveIfError(r);
if (r == KErrNone) {
r = server.GetPortInfo(KBluetoothModuleName, nativeSerialInfo);
if (r == KErrNone) {
for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = s
.arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length()))
.arg(i);
serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device;
serialPortInfo.d_ptr->description =
QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length());
serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
serialPortInfoList.append(serialPortInfo);
}
}
}
// FIXME: Get info about InfraRed ports.
r = server.LoadCommModule(KInfraRedModuleName);
//User::LeaveIfError(r);
if (r == KErrNone) {
r = server.GetPortInfo(KInfraRedModuleName, nativeSerialInfo);
if (r == KErrNone) {
for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = s
.arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length()))
.arg(i);
serialPortInfo.d_ptr->portName = serialPortInfo.d_ptr->device;
serialPortInfo.d_ptr->description =
QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length());
serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
serialPortInfoList.append(serialPortInfo);
}
}
}
// FIXME: Get info about ACM ports.
r = server.LoadCommModule(KACMModuleName);
//User::LeaveIfError(r);
if (r == KErrNone) {
r = server.GetPortInfo(KACMModuleName, nativeSerialInfo);
if (r == KErrNone) {
for (quint32 i = nativeSerialInfo.iLowUnit; i < nativeSerialInfo.iHighUnit + 1; ++i) {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = s
.arg(QString::fromUtf16(nativeSerialInfo.iName.Ptr(), nativeSerialInfo.iName.Length()))
.arg(i);
serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device);
serialPortInfo.d_ptr->description =
QString::fromUtf16(nativeSerialInfo.iDescription.Ptr(), nativeSerialInfo.iDescription.Length());
serialPortInfo.d_ptr->manufacturer = QString(QObject::tr("Unknown."));
serialPortInfoList.append(serialPortInfo);
}
}
}
return serialPortInfoList;
}
QList<qint32> QSerialPortInfo::standardBaudRates()
{
return QSerialPortPrivate::standardBaudRates();
}
bool QSerialPortInfo::isBusy() const
{
if (!loadDevices())
return false;
RCommServ server;
TInt r = server.Connect();
if (r != KErrNone)
return false;
RComm port;
TPtrC portName(static_cast<const TUint16*>(systemLocation().utf16()), systemLocation().length());
r = port.Open(server, portName, ECommExclusive);
if (r == KErrNone)
port.Close();
return r == KErrLocked;
}
bool QSerialPortInfo::isValid() const
{
if (!loadDevices())
return false;
RCommServ server;
TInt r = server.Connect();
if (r != KErrNone)
return false;
RComm port;
TPtrC portName(static_cast<const TUint16*>(systemLocation().utf16()), systemLocation().length());
r = port.Open(server, portName, ECommExclusive);
if (r == KErrNone)
port.Close();
return r == KErrNone || r == KErrLocked;
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include "qttylocker_unix_p.h"
#include "qserialport_unix_p.h"
#include <QtCore/qfile.h>
#ifndef Q_OS_MAC
#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
extern "C"
{
#include <libudev.h>
}
#else
#include <QtCore/qdir.h>
#include <QtCore/qstringlist.h>
#endif
#endif // Q_OS_MAC
QT_BEGIN_NAMESPACE
#ifndef Q_OS_MAC
#if !(defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV))
static inline const QStringList& filtersOfDevices()
{
static const QStringList deviceFileNameFilterList = QStringList()
# ifdef Q_OS_LINUX
<< QLatin1String("ttyS*") // Standart UART 8250 and etc.
<< QLatin1String("ttyUSB*") // Usb/serial converters PL2303 and etc.
<< QLatin1String("ttyACM*") // CDC_ACM converters (i.e. Mobile Phones).
<< QLatin1String("ttyGS*") // Gadget serial device (i.e. Mobile Phones with gadget serial driver).
<< QLatin1String("ttyMI*") // MOXA pci/serial converters.
<< QLatin1String("ttyAMA*") // AMBA serial device for embedded platform on ARM (i.e. Raspberry Pi).
<< QLatin1String("rfcomm*") // Bluetooth serial device.
<< QLatin1String("ircomm*"); // IrDA serial device.
# elif defined (Q_OS_FREEBSD)
<< QLatin1String("cu*");
# else
; // Here for other *nix OS.
# endif
return deviceFileNameFilterList;
}
#endif
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
QList<QSerialPortInfo> serialPortInfoList;
#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
// White list for devices without a parent
static const QString rfcommDeviceName(QLatin1String("rfcomm"));
struct ::udev *udev = ::udev_new();
if (udev) {
struct ::udev_enumerate *enumerate =
::udev_enumerate_new(udev);
if (enumerate) {
::udev_enumerate_add_match_subsystem(enumerate, "tty");
::udev_enumerate_scan_devices(enumerate);
struct ::udev_list_entry *devices =
::udev_enumerate_get_list_entry(enumerate);
struct ::udev_list_entry *dev_list_entry;
udev_list_entry_foreach(dev_list_entry, devices) {
struct ::udev_device *dev =
::udev_device_new_from_syspath(udev,
::udev_list_entry_get_name(dev_list_entry));
if (dev) {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device =
QLatin1String(::udev_device_get_devnode(dev));
serialPortInfo.d_ptr->portName =
QLatin1String(::udev_device_get_sysname(dev));
struct ::udev_device *parentdev = ::udev_device_get_parent(dev);
bool canAppendToList = true;
if (parentdev) {
QLatin1String subsys(::udev_device_get_subsystem(parentdev));
if (subsys == QLatin1String("usb-serial")
|| subsys == QLatin1String("usb")) { // USB bus type
// Append this devices and try get additional information about them.
serialPortInfo.d_ptr->description = QString(
QLatin1String(::udev_device_get_property_value(dev,
"ID_MODEL"))).replace('_', ' ');
serialPortInfo.d_ptr->manufacturer = QString(
QLatin1String(::udev_device_get_property_value(dev,
"ID_VENDOR"))).replace('_', ' ');
serialPortInfo.d_ptr->vendorIdentifier =
QString::fromLatin1(::udev_device_get_property_value(dev,
"ID_VENDOR_ID")).toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16);
serialPortInfo.d_ptr->productIdentifier =
QString::fromLatin1(::udev_device_get_property_value(dev,
"ID_MODEL_ID")).toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16);
} else if (subsys == QLatin1String("pnp")) { // PNP bus type
// Append this device.
// FIXME: How to get additional information about serial devices
// with this subsystem?
} else if (subsys == QLatin1String("platform")) { // Platform 'pseudo' bus for legacy device.
// Skip this devices because this type of subsystem does
// not include a real physical serial device.
canAppendToList = false;
} else { // Others types of subsystems.
// Append this devices because we believe that any other types of
// subsystems provide a real serial devices. For example, for devices
// such as ttyGSx, its driver provide an empty subsystem name, but it
// devices is a real physical serial devices.
// FIXME: How to get additional information about serial devices
// with this subsystems?
}
} else { // Devices without a parent
if (serialPortInfo.d_ptr->portName.startsWith(rfcommDeviceName)) { // Bluetooth device
bool ok;
// Check for an unsigned decimal integer at the end of the device name: "rfcomm0", "rfcomm15"
// devices with negative and invalid numbers in the name are rejected
int portNumber = serialPortInfo.d_ptr->portName.mid(rfcommDeviceName.length()).toInt(&ok);
if (!ok || (portNumber < 0) || (portNumber > 255)) {
canAppendToList = false;
}
} else {
canAppendToList = false;
}
}
if (canAppendToList)
serialPortInfoList.append(serialPortInfo);
::udev_device_unref(dev);
}
}
::udev_enumerate_unref(enumerate);
}
::udev_unref(udev);
}
#elif defined (Q_OS_FREEBSD) && defined (HAVE_LIBUSB)
// TODO: Implement me.
#else
QDir devDir(QLatin1String("/dev"));
if (devDir.exists()) {
devDir.setNameFilters(filtersOfDevices());
devDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks);
QStringList foundDevices; // Found devices list.
foreach (const QFileInfo &deviceFileInfo, devDir.entryInfoList()) {
QString deviceFilePath = deviceFileInfo.absoluteFilePath();
if (!foundDevices.contains(deviceFilePath)) {
foundDevices.append(deviceFilePath);
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = deviceFilePath;
serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath);
// Get description, manufacturer, vendor identifier, product
// identifier are not supported.
serialPortInfoList.append(serialPortInfo);
}
}
}
#endif
return serialPortInfoList;
}
#endif // Q_OS_MAC
// common part
QList<qint32> QSerialPortInfo::standardBaudRates()
{
return QSerialPortPrivate::standardBaudRates();
}
bool QSerialPortInfo::isBusy() const
{
bool currentPid = false;
return QTtyLocker::isLocked(portName().toLocal8Bit().constData(), &currentPid);
}
bool QSerialPortInfo::isValid() const
{
QFile f(systemLocation());
return f.exists();
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include "qserialport_win_p.h"
#ifndef Q_OS_WINCE
#include <initguid.h>
#include <setupapi.h>
#endif
#include <QtCore/qvariant.h>
#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINCE
static const GUID guidsArray[] =
{
// Windows Ports Class GUID
{ 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
// Virtual Ports Class GUID (i.e. com0com and etc)
{ 0xDF799E12, 0x3C56, 0x421B, { 0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78 } },
// Windows Modems Class GUID
{ 0x4D36E96D, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },
// Eltima Virtual Serial Port Driver v4 GUID
{ 0xCC0EF009, 0xB820, 0x42F4, { 0x95, 0xA9, 0x9B, 0xFA, 0x6A, 0x5A, 0xB7, 0xAB } },
// Advanced Virtual COM Port GUID
{ 0x9341CD95, 0x4371, 0x4A37, { 0xA5, 0xAF, 0xFD, 0xB0, 0xA9, 0xD1, 0x96, 0x31 } },
};
static QVariant deviceRegistryProperty(HDEVINFO deviceInfoSet,
PSP_DEVINFO_DATA deviceInfoData,
DWORD property)
{
DWORD dataType = 0;
DWORD dataSize = 0;
::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData,
property, &dataType, NULL, 0, &dataSize);
QByteArray data(dataSize, 0);
if (!::SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, NULL,
reinterpret_cast<unsigned char*>(data.data()),
dataSize, NULL)
|| !dataSize) {
return QVariant();
}
switch (dataType) {
case REG_EXPAND_SZ:
case REG_SZ: {
return QVariant(QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData())));
}
case REG_MULTI_SZ: {
QStringList list;
int i = 0;
forever {
QString s = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()) + i);
i += s.length() + 1;
if (s.isEmpty())
break;
list.append(s);
}
return QVariant(list);
}
default:
break;
}
return QVariant();
}
static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData)
{
static const wchar_t portKeyName[] = L"PortName";
const HKEY key = ::SetupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, DICS_FLAG_GLOBAL,
0, DIREG_DEV, KEY_READ);
if (key == INVALID_HANDLE_VALUE)
return QString();
DWORD dataSize;
if (::RegQueryValueEx(key, portKeyName, NULL, NULL, NULL, &dataSize) != ERROR_SUCCESS) {
::RegCloseKey(key);
return QString();
}
QByteArray data(dataSize, 0);
if (::RegQueryValueEx(key, portKeyName, NULL, NULL,
reinterpret_cast<unsigned char *>(data.data()), &dataSize) != ERROR_SUCCESS) {
::RegCloseKey(key);
return QString();
}
::RegCloseKey(key);
return QString::fromWCharArray(((const wchar_t *)data.constData()));
}
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
static const QString vendorIdentifierPrefix(QLatin1String("VID_"));
static const int vendorIdentifierSize = 4;
static const QString productIdentifierPrefix(QLatin1String("PID_"));
static const int productIdentifierSize = 4;
QList<QSerialPortInfo> serialPortInfoList;
static const int guidCount = sizeof(guidsArray)/sizeof(guidsArray[0]);
for (int i = 0; i < guidCount; ++i) {
const HDEVINFO deviceInfoSet = ::SetupDiGetClassDevs(&guidsArray[i], NULL, 0, DIGCF_PRESENT);
if (deviceInfoSet == INVALID_HANDLE_VALUE)
return serialPortInfoList;
SP_DEVINFO_DATA deviceInfoData;
::memset(&deviceInfoData, 0, sizeof(deviceInfoData));
deviceInfoData.cbSize = sizeof(deviceInfoData);
DWORD index = 0;
while (::SetupDiEnumDeviceInfo(deviceInfoSet, index++, &deviceInfoData)) {
QSerialPortInfo serialPortInfo;
QString s = devicePortName(deviceInfoSet, &deviceInfoData);
if (s.isEmpty() || s.contains(QLatin1String("LPT")))
continue;
serialPortInfo.d_ptr->portName = s;
serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(s);
serialPortInfo.d_ptr->description =
deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_DEVICEDESC).toString();
serialPortInfo.d_ptr->manufacturer =
deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG).toString();
s = deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID).toStringList().first().toUpper();
int index = s.indexOf(vendorIdentifierPrefix);
if (index != -1)
serialPortInfo.d_ptr->vendorIdentifier = s.mid(index + vendorIdentifierPrefix.size(), vendorIdentifierSize)
.toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16);
index = s.indexOf(productIdentifierPrefix);
if (index != -1)
serialPortInfo.d_ptr->productIdentifier = s.mid(index + productIdentifierPrefix.size(), productIdentifierSize)
.toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16);
serialPortInfoList.append(serialPortInfo);
}
::SetupDiDestroyDeviceInfoList(deviceInfoSet);
}
return serialPortInfoList;
}
#endif
// common part
QList<qint32> QSerialPortInfo::standardBaudRates()
{
return QSerialPortPrivate::standardBaudRates();
}
bool QSerialPortInfo::isBusy() const
{
const HANDLE descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()),
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (descriptor == INVALID_HANDLE_VALUE) {
if (::GetLastError() == ERROR_ACCESS_DENIED)
return true;
} else {
::CloseHandle(descriptor);
}
return false;
}
bool QSerialPortInfo::isValid() const
{
const HANDLE descriptor = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation().utf16()),
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (descriptor == INVALID_HANDLE_VALUE) {
if (::GetLastError() != ERROR_ACCESS_DENIED)
return false;
} else {
::CloseHandle(descriptor);
}
return true;
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qserialportinfo.h"
#include "qserialportinfo_p.h"
#include "qserialport_win_p.h"
#include <QtCore/qstringlist.h>
QT_BEGIN_NAMESPACE
static QString findDescription(HKEY parentKeyHandle, const QString &subKey)
{
const static QString valueName(QLatin1String("FriendlyName"));
QString result;
HKEY hSubKey = 0;
LONG res = ::RegOpenKeyEx(parentKeyHandle, reinterpret_cast<const wchar_t *>(subKey.utf16()),
0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hSubKey);
if (res == ERROR_SUCCESS) {
DWORD dataType = 0;
DWORD dataSize = 0;
res = ::RegQueryValueEx(hSubKey, reinterpret_cast<const wchar_t *>(valueName.utf16()),
NULL, &dataType, NULL, &dataSize);
if (res == ERROR_SUCCESS) {
QByteArray data(dataSize, 0);
res = ::RegQueryValueEx(hSubKey, reinterpret_cast<const wchar_t *>(valueName.utf16()),
NULL, NULL,
reinterpret_cast<unsigned char *>(data.data()),
&dataSize);
if (res == ERROR_SUCCESS) {
switch (dataType) {
case REG_EXPAND_SZ:
case REG_SZ:
if (dataSize)
result = QString::fromWCharArray(reinterpret_cast<const wchar_t *>(data.constData()));
break;
default:
break;
}
}
} else {
DWORD index = 0;
dataSize = 255; // Max. key length (see MSDN).
QByteArray data(dataSize, 0);
while (::RegEnumKeyEx(hSubKey, index++,
reinterpret_cast<wchar_t *>(data.data()), &dataSize,
NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
result = findDescription(hSubKey,
QString::fromUtf16(reinterpret_cast<ushort *>(data.data()), dataSize));
if (!result.isEmpty())
break;
}
}
::RegCloseKey(hSubKey);
}
return result;
}
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
QList<QSerialPortInfo> serialPortInfoList;
DEVMGR_DEVICE_INFORMATION di;
di.dwSize = sizeof(di);
const HANDLE hSearch = ::FindFirstDevice(DeviceSearchByLegacyName,
L"COM*",
&di);
if (hSearch != INVALID_HANDLE_VALUE) {
do {
QSerialPortInfo serialPortInfo;
serialPortInfo.d_ptr->device = QString::fromWCharArray(di.szLegacyName);
serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(serialPortInfo.d_ptr->device);
serialPortInfo.d_ptr->description = findDescription(HKEY_LOCAL_MACHINE,
QString::fromWCharArray(di.szDeviceKey));
// Get manufacturer, vendor identifier, product identifier are not
// possible.
serialPortInfoList.append(serialPortInfo);
} while (::FindNextDevice(hSearch, &di));
::FindClose(hSearch);
}
return serialPortInfoList;
}
QT_END_NAMESPACE
QTSERIALPORT_PROJECT_INCLUDEDIR = $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort
QTSERIALPORT_PROJECT_INCLUDEDIR ~=s,/,$$QMAKE_DIR_SEP,
system("$$QMAKE_MKDIR $$QTSERIALPORT_PROJECT_INCLUDEDIR")
for(header_file, PUBLIC_HEADERS) {
header_file ~=s,/,$$QMAKE_DIR_SEP,
system("$$QMAKE_COPY \"$${header_file}\" \"$$QTSERIALPORT_PROJECT_INCLUDEDIR\"")
}
# This is a quick workaround for generating forward header with Qt4.
unix {
system("echo \'$${LITERAL_HASH}include \"qserialport.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"")
system("echo \'$${LITERAL_HASH}include \"qserialportinfo.h\"\' > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"")
} win32 {
system("echo $${LITERAL_HASH}include \"qserialport.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\"")
system("echo $${LITERAL_HASH}include \"qserialportinfo.h\" > \"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"")
}
PUBLIC_HEADERS += \
$$PUBLIC_HEADERS \
\"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPort\" \
\"$$QTSERIALPORT_PROJECT_INCLUDEDIR/QSerialPortInfo\"
target_headers.files = $$PUBLIC_HEADERS
target_headers.path = $$[QT_INSTALL_PREFIX]/include/QtSerialPort
INSTALLS += target_headers
mkspecs_features.files = $$QTSERIALPORT_PROJECT_ROOT/src/serialport/qt4support/serialport.prf
mkspecs_features.path = $$[QT_INSTALL_DATA]/mkspecs/features
INSTALLS += mkspecs_features
win32 {
dlltarget.path = $$[QT_INSTALL_BINS]
INSTALLS += dlltarget
}
target.path = $$[QT_INSTALL_LIBS]
INSTALLS += target
INCLUDEPATH += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort
DEFINES += QT_BUILD_SERIALPORT_LIB
/****************************************************************************
**
** 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 <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
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<QByteArray> buffers;
int head, tail;
int tailBuffer; // always buffers.size() - 1
int basicBlockSize;
int bufferSize;
};
QT_END_NAMESPACE
#endif // QRINGBUFFER_P_H
/****************************************************************************
**
** 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
qtAddLibrary(QtSerialPort)
!isEmpty(QTSERIALPORT_BUILD_ROOT) {
INCLUDEPATH -= $$QMAKE_INCDIR_QT/QtSerialPort
QMAKE_INCDIR += $$QTSERIALPORT_BUILD_ROOT/include $$QTSERIALPORT_BUILD_ROOT/include/QtSerialPort
QTSERIALPORT_BUILD_SUBDIR = src/serialport
debug_and_release_target {
CONFIG(debug, debug|release) {
QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/debug
} else {
QTSERIALPORT_BUILD_SUBDIR = $$QTSERIALPORT_BUILD_SUBDIR/release
}
}
QMAKE_LIBDIR += $$QTSERIALPORT_BUILD_ROOT/$$QTSERIALPORT_BUILD_SUBDIR
}
mac {
LIBS -= -framework QtSerialPort$${QT_LIBINFIX}
if(!debug_and_release|build_pass):CONFIG(debug, debug|release) {
LIBS += -lQtSerialPort$${QT_LIBINFIX}_debug
} else {
LIBS += -lQtSerialPort$${QT_LIBINFIX}
}
}
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include "qttylocker_unix_p.h"
#ifdef HAVE_BAUDBOY_H
# include <baudboy.h>
# include <cstdlib>
#elif defined (HAVE_LOCKDEV_H)
# include <lockdev.h>
# include <unistd.h>
#else
# include <signal.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <unistd.h>
# include <QtCore/qfile.h>
# include <QtCore/qdir.h>
# include <QtCore/qstringlist.h>
#endif // defined (HAVE_BAUDBOY_H)
QT_BEGIN_NAMESPACE
#if !(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H))
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
# define QStringLiteral QLatin1String
#endif
static inline const QStringList& lockDirectoryList()
{
static const QStringList lockDirectoryEntries = QStringList()
<< QStringLiteral("/var/lock")
<< QStringLiteral("/etc/locks")
<< QStringLiteral("/var/spool/locks")
<< QStringLiteral("/var/spool/uucp")
<< QStringLiteral("/tmp");
return lockDirectoryEntries;
}
// Returns the full path first found in the directory where you can create a lock file
// (ie a directory with access to the read/write).
// Verification of directories is of the order in accordance with the order
// of records in the variable lockDirList.
static
QString lookupFirstSharedLockDir()
{
QStringList directoryList = lockDirectoryList();
foreach (const QString &lockDirectory, directoryList) {
if (::access(lockDirectory.toLocal8Bit().constData(), R_OK | W_OK) == 0)
return lockDirectory;
}
return QString();
}
// Returns the name of the lock file which is tied to the
// device name, eg "LCK..ttyS0", etc.
static
QString generateLockFileNameAsNamedForm(const char *portName)
{
QString result(lookupFirstSharedLockDir());
if (!result.isEmpty()) {
result.append(QLatin1String("/LCK.."));
result.append(QString::fromLatin1(portName).replace(QLatin1Char('/'), QLatin1Char('_')));
}
return result;
}
#endif //!(defined (HAVE_BAUDBOY_H) || defined (HAVE_LOCKDEV_H))
// Try lock serial device. However, other processes can not access it.
bool QTtyLocker::lock(const char *portName)
{
#ifdef HAVE_BAUDBOY_H
if (::ttylock(portName)
::ttywait(portName);
return ::ttylock(portName) != -1;
#elif defined (HAVE_LOCKDEV_H)
return ::dev_lock(portName) != -1;
#else
QFile f(generateLockFileNameAsNamedForm(portName));
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QString content(QLatin1String(" %1 %2\x0A"));
content = content.arg(::getpid()).arg(::getuid());
if (f.write(content.toLocal8Bit()) > 0) {
f.close();
return true;
}
f.close();
}
return false;
#endif
}
// Try unlock serial device. However, other processes can access it.
bool QTtyLocker::unlock(const char *portName)
{
#ifdef HAVE_BAUDBOY_H
return ::ttyunlock(portName != -1;
#elif defined (HAVE_LOCKDEV_H)
return ::dev_unlock(portName, ::getpid()) != -1;
#else
QFile f(generateLockFileNameAsNamedForm(portName));
return f.remove();
#endif
}
// Verifies the device is locked or not.
// If returned currentPid = true - this means that the device is locked the current process.
bool QTtyLocker::isLocked(const char *portName, bool *currentPid)
{
if (!currentPid)
return true;
*currentPid = false;
#ifdef HAVE_BAUDBOY_H
return ::ttylocked(portName) != -1;
#elif defined (HAVE_LOCKDEV_H)
return ::dev_testlock(portName) != -1;
#else
QFile f(generateLockFileNameAsNamedForm(portName));
if (!f.exists())
return false;
if (!f.open(QIODevice::ReadOnly))
return true;
QString content(QLatin1String(f.readAll()));
f.close();
const pid_t pid = content.section(' ', 0, 0, QString::SectionSkipEmpty).toInt();
if (::kill(pid, 0) == -1) {
if (errno == ESRCH) // Process does not exists
return false;
} else {
if (::getpid() == pid) // Process exists and it is "their", i.e current
*currentPid = true;
}
return true;
#endif
}
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSerialPort 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$
**
****************************************************************************/
#include <QtCore/qglobal.h>
#ifndef TTYLOCKER_UNIX_P_H
#define TTYLOCKER_UNIX_P_H
QT_BEGIN_NAMESPACE
class QTtyLocker
{
public:
static bool lock(const char *portName);
static bool unlock(const char *portName);
static bool isLocked(const char *portName, bool *currentPid);
};
QT_END_NAMESPACE
#endif // TTYLOCKER_UNIX_P_H
INCLUDEPATH += $$PWD
unix {
CONFIG += link_pkgconfig
packagesExist(libudev) {
DEFINES += HAVE_LIBUDEV
PKGCONFIG += libudev
}
}
PUBLIC_HEADERS += \
$$PWD/qserialportglobal.h \
$$PWD/qserialport.h \
$$PWD/qserialportinfo.h
PRIVATE_HEADERS += \
$$PWD/qserialport_p.h \
$$PWD/qserialportinfo_p.h
SOURCES += \
$$PWD/qserialport.cpp \
$$PWD/qserialportinfo.cpp
win32 {
PRIVATE_HEADERS += \
$$PWD/qserialport_win_p.h
SOURCES += \
$$PWD/qserialport_win.cpp \
$$PWD/qserialportinfo_win.cpp
!wince*: {
LIBS += -lsetupapi -ladvapi32
} else {
SOURCES += \
$$PWD/qserialport_wince.cpp \
$$PWD/qserialportinfo_wince.cpp
}
}
symbian {
MMP_RULES += EXPORTUNFROZEN
#MMP_RULES += DEBUGGABLE_UDEBONLY
TARGET.UID3 = 0xE7E62DFD
TARGET.CAPABILITY =
TARGET.EPOCALLOWDLLDATA = 1
addFiles.sources = QtSerialPort.dll
addFiles.path = !:/sys/bin
DEPLOYMENT += addFiles
# FIXME !!!
#INCLUDEPATH += c:/Nokia/devices/Nokia_Symbian3_SDK_v1.0/epoc32/include/platform
INCLUDEPATH += c:/QtSDK/Symbian/SDKs/Symbian3Qt473/epoc32/include/platform
PRIVATE_HEADERS += \
$$PWD/qserialport_symbian_p.h
SOURCES += \
$$PWD/qserialport_symbian.cpp \
$$PWD/qserialportinfo_symbian.cpp
LIBS += -leuser -lefsrv -lc32
}
unix:!symbian {
PRIVATE_HEADERS += \
$$PWD/qttylocker_unix_p.h \
$$PWD/qserialport_unix_p.h
SOURCES += \
$$PWD/qttylocker_unix.cpp \
$$PWD/qserialport_unix.cpp \
$$PWD/qserialportinfo_unix.cpp
macx {
SOURCES += $$PWD/qserialportinfo_mac.cpp
LIBS += -framework IOKit -framework CoreFoundation
} else {
linux*:contains( DEFINES, HAVE_LIBUDEV ) {
LIBS += -ludev
}
}
}
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
QT = core
QMAKE_DOCS = $$PWD/doc/qtserialport.qdocconf
include($$PWD/serialport-lib.pri)
greaterThan(QT_MAJOR_VERSION, 4) {
load(qt_build_config)
QT += core-private
TARGET = QtSerialPort
load(qt_module)
} else {
TEMPLATE = lib
TARGET = $$qtLibraryTarget(QtSerialPort$$QT_LIBINFIX)
include($$PWD/qt4support/install-helper.pri)
CONFIG += module create_prl
mac:QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET
}
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
# Qt configuration # Qt configuration
CONFIG += qt \ CONFIG += qt \
thread thread \
QT += network \ QT += network \
opengl \ opengl \
svg \ svg \
...@@ -93,7 +94,7 @@ DEPENDPATH += \ ...@@ -93,7 +94,7 @@ DEPENDPATH += \
INCLUDEPATH += \ INCLUDEPATH += \
libs/utils \ libs/utils \
libs \ libs \
libs/opmapcontrol libs/opmapcontrol \
# If the user config file exists, it will be included. # If the user config file exists, it will be included.
# if the variable MAVLINK_CONF contains the name of an # if the variable MAVLINK_CONF contains the name of an
...@@ -135,30 +136,22 @@ INCLUDEPATH += \ ...@@ -135,30 +136,22 @@ INCLUDEPATH += \
include(src/apps/mavlinkgen/mavlinkgen.pri) include(src/apps/mavlinkgen/mavlinkgen.pri)
# Include QWT plotting library # Include QWT plotting library
include(libs/qwt/qwt.pri) include(libs/qwt/qwt.pri)
DEPENDPATH += . \ DEPENDPATH += . \
plugins \ plugins
libs/thirdParty/qserialport/include \
libs/thirdParty/qserialport/include/QtSerialPort \ INCLUDEPATH += .
libs/thirdParty/qserialport \
libs/qextserialport # Include serial port library (QSerialPort)
include(libs/serialport/apmserial.pri)
INCLUDEPATH += . \
libs/thirdParty/qserialport/include \ ## Serial port detection (ripped-off from qextserialport library)
libs/thirdParty/qserialport/include/QtSerialPort \ #macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp
libs/thirdParty/qserialport/src \ #linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp
libs/qextserialport #linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp
# Include serial port library (QSerial) #win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp
include(qserialport.pri)
# Serial port detection (ripped-off from qextserialport library)
macx|macx-g++|macx-g++42::SOURCES += libs/qextserialport/qextserialenumerator_osx.cpp
linux-g++::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp
linux-g++-64::SOURCES += libs/qextserialport/qextserialenumerator_unix.cpp
win32-msvc2008|win32-msvc2010|win32-msvc2012::SOURCES += libs/qextserialport/qextserialenumerator_win.cpp
# Input # Input
FORMS += src/ui/MainWindow.ui \ FORMS += src/ui/MainWindow.ui \
src/ui/CommSettings.ui \ src/ui/CommSettings.ui \
...@@ -345,7 +338,7 @@ HEADERS += src/MG.h \ ...@@ -345,7 +338,7 @@ HEADERS += src/MG.h \
src/ui/map/Waypoint2DIcon.h \ src/ui/map/Waypoint2DIcon.h \
src/ui/map/QGCMapTool.h \ src/ui/map/QGCMapTool.h \
src/ui/map/QGCMapToolBar.h \ src/ui/map/QGCMapToolBar.h \
libs/qextserialport/qextserialenumerator.h \ # libs/qextserialport/qextserialenumerator.h \
src/QGCGeo.h \ src/QGCGeo.h \
src/ui/QGCToolBar.h \ src/ui/QGCToolBar.h \
src/ui/QGCStatusBar.h \ src/ui/QGCStatusBar.h \
......
...@@ -12,257 +12,62 @@ ...@@ -12,257 +12,62 @@
#include <QDebug> #include <QDebug>
#include <QSettings> #include <QSettings>
#include <QMutexLocker> #include <QMutexLocker>
#include <qserialport.h>
#include <qserialportinfo.h>
#include "SerialLink.h" #include "SerialLink.h"
#include "LinkManager.h" #include "LinkManager.h"
#include "QGC.h" #include "QGC.h"
#include <MG.h> #include <MG.h>
#include <iostream>
#ifdef _WIN32
#include "windows.h"
#endif
#ifdef _WIN32
#include <qextserialenumerator.h>
#endif
#if defined (__APPLE__) && defined (__MACH__)
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <termios.h>
#include <sysexits.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <AvailabilityMacros.h>
#ifdef __MWERKS__
#define __CF_USE_FRAMEWORK_INCLUDES__
#endif
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
#include <IOKit/serial/ioss.h>
#endif
#include <IOKit/IOBSD.h>
// Apple internal modems default to local echo being on. If your modem has local echo disabled,
// undefine the following macro.
#define LOCAL_ECHO
#define kATCommandString "AT\r"
#ifdef LOCAL_ECHO
#define kOKResponseString "AT\r\r\nOK\r\n"
#else
#define kOKResponseString "\r\nOK\r\n"
#endif
#endif
// Some helper functions for serial port enumeration
#if defined (__APPLE__) && defined (__MACH__)
enum {
kNumRetries = 3
};
// Function prototypes
static kern_return_t FindModems(io_iterator_t *matchingServices);
static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize);
// Returns an iterator across all known modems. Caller is responsible for
// releasing the iterator when iteration is complete.
static kern_return_t FindModems(io_iterator_t *matchingServices)
{
kern_return_t kernResult;
CFMutableDictionaryRef classesToMatch;
/*! @function IOServiceMatching
@abstract Create a matching dictionary that specifies an IOService class match.
@discussion A very common matching criteria for IOService is based on its class. IOServiceMatching will create a matching dictionary that specifies any IOService of a class, or its subclasses. The class is specified by C-string name.
@param name The class name, as a const C-string. Class matching is successful on IOService's of this class or any subclass.
@result The matching dictionary created, is returned on success, or zero on failure. The dictionary is commonly passed to IOServiceGetMatchingServices or IOServiceAddNotification which will consume a reference, otherwise it should be released with CFRelease by the caller. */
// Serial devices are instances of class IOSerialBSDClient
classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
if (classesToMatch == NULL) {
printf("IOServiceMatching returned a NULL dictionary.\n");
} else {
/*!
@function CFDictionarySetValue
Sets the value of the key in the dictionary.
@param theDict The dictionary to which the value is to be set. If this
parameter is not a valid mutable CFDictionary, the behavior is
undefined. If the dictionary is a fixed-capacity dictionary and
it is full before this operation, and the key does not exist in
the dictionary, the behavior is undefined.
@param key The key of the value to set into the dictionary. If a key
which matches this key is already present in the dictionary, only
the value is changed ("add if absent, replace if present"). If
no key matches the given key, the key-value pair is added to the
dictionary. If added, the key is retained by the dictionary,
using the retain callback provided
when the dictionary was created. If the key is not of the sort
expected by the key retain callback, the behavior is undefined.
@param value The value to add to or replace into the dictionary. The value
is retained by the dictionary using the retain callback provided
when the dictionary was created, and the previous value if any is
released. If the value is not of the sort expected by the
retain or release callbacks, the behavior is undefined.
*/
CFDictionarySetValue(classesToMatch,
CFSTR(kIOSerialBSDTypeKey),
CFSTR(kIOSerialBSDModemType));
// Each serial device object has a property with key
// kIOSerialBSDTypeKey and a value that is one of kIOSerialBSDAllTypes,
// kIOSerialBSDModemType, or kIOSerialBSDRS232Type. You can experiment with the
// matching by changing the last parameter in the above call to CFDictionarySetValue.
// As shipped, this sample is only interested in modems,
// so add this property to the CFDictionary we're matching on.
// This will find devices that advertise themselves as modems,
// such as built-in and USB modems. However, this match won't find serial modems.
}
/*! @function IOServiceGetMatchingServices
@abstract Look up registered IOService objects that match a matching dictionary.
@discussion This is the preferred method of finding IOService objects currently registered by IOKit. IOServiceAddNotification can also supply this information and install a notification of new IOServices. The matching information used in the matching dictionary may vary depending on the class of service being looked up.
@param masterPort The master port obtained from IOMasterPort().
@param matching A CF dictionary containing matching information, of which one reference is consumed by this function. IOKitLib can contruct matching dictionaries for common criteria with helper functions such as IOServiceMatching, IOOpenFirmwarePathMatching.
@param existing An iterator handle is returned on success, and should be released by the caller when the iteration is finished.
@result A kern_return_t error code. */
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, matchingServices);
if (KERN_SUCCESS != kernResult) {
printf("IOServiceGetMatchingServices returned %d\n", kernResult);
goto exit;
}
exit:
return kernResult;
}
/** Given an iterator across a set of modems, return the BSD path to the first one.
* If no modems are found the path name is set to an empty string.
*/
static kern_return_t GetModemPath(io_iterator_t serialPortIterator, char *bsdPath, CFIndex maxPathSize)
{
io_object_t modemService;
kern_return_t kernResult = KERN_FAILURE;
Boolean modemFound = false;
// Initialize the returned path
*bsdPath = '\0';
// Iterate across all modems found. In this example, we bail after finding the first modem.
while ((modemService = IOIteratorNext(serialPortIterator)) && !modemFound) {
CFTypeRef bsdPathAsCFString;
// Get the callout device's path (/dev/cu.xxxxx). The callout device should almost always be
// used: the dialin device (/dev/tty.xxxxx) would be used when monitoring a serial port for
// incoming calls, e.g. a fax listener.
bsdPathAsCFString = IORegistryEntryCreateCFProperty(modemService,
CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault,
0);
if (bsdPathAsCFString) {
Boolean result;
// Convert the path from a CFString to a C (NUL-terminated) string for use
// with the POSIX open() call.
result = CFStringGetCString((CFStringRef)bsdPathAsCFString,
bsdPath,
maxPathSize,
kCFStringEncodingUTF8);
CFRelease(bsdPathAsCFString);
if (result) {
//printf("Modem found with BSD path: %s", bsdPath);
modemFound = true;
kernResult = KERN_SUCCESS;
}
}
printf("\n");
// Release the io_service_t now that we are done with it.
(void) IOObjectRelease(modemService);
}
return kernResult;
}
#endif
using namespace TNX;
SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity, SerialLink::SerialLink(QString portname, int baudRate, bool hardwareFlowControl, bool parity,
int dataBits, int stopBits) : int dataBits, int stopBits) :
port(NULL), m_bytesRead(0),
ports(new QVector<QString>()), m_port(NULL),
m_ports(new QVector<QString>()),
m_stopp(false), m_stopp(false),
bytesRead(0),
m_reqReset(false) m_reqReset(false)
{ {
// Setup settings // Setup settings
this->porthandle = portname.trimmed(); m_portName = portname.trimmed();
if (this->porthandle == "" && getCurrentPorts()->size() > 0) if (m_portName == "" && getCurrentPorts()->size() > 0)
{ {
this->porthandle = getCurrentPorts()->first().trimmed(); m_portName = m_ports->first().trimmed();
} }
#ifdef _WIN32
// Port names above 20 need the network path format - if the port name is not already in this format
// catch this special case
if (this->porthandle.size() > 0 && !this->porthandle.startsWith("\\")) {
// Append \\.\ before the port handle. Additional backslashes are used for escaping.
this->porthandle = "\\\\.\\" + this->porthandle;
}
#endif
// Set unique ID and add link to the list of links // Set unique ID and add link to the list of links
this->id = getNextLinkId(); m_id = getNextLinkId();
m_baud = baudRate;
setBaudRate(baudRate);
if (hardwareFlowControl) if (hardwareFlowControl)
{ {
portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE); m_flowControl = QSerialPort::HardwareControl;
} }
else else
{ {
portSettings.setFlowControl(QPortSettings::FLOW_OFF); m_flowControl = QSerialPort::NoFlowControl;
} }
if (parity) if (parity)
{ {
portSettings.setParity(QPortSettings::PAR_EVEN); m_parity = QSerialPort::EvenParity;
} }
else else
{ {
portSettings.setParity(QPortSettings::PAR_NONE); m_parity = QSerialPort::NoParity;
} }
setDataBits(dataBits);
setStopBits(stopBits); m_dataBits = dataBits;
m_stopBits = stopBits;
// Set the port name // Set the port name
if (porthandle == "") if (m_portName == "")
{ {
name = tr("Serial Link ") + QString::number(getId()); m_name = tr("Serial Link ") + QString::number(getId());
} }
else else
{ {
name = portname.trimmed(); m_name = portname.trimmed();
} }
loadSettings(); loadSettings();
} }
...@@ -275,91 +80,26 @@ void SerialLink::requestReset() ...@@ -275,91 +80,26 @@ void SerialLink::requestReset()
SerialLink::~SerialLink() SerialLink::~SerialLink()
{ {
disconnect(); disconnect();
if(port) delete port; if(m_port) delete m_port;
port = NULL; m_port = NULL;
if (ports) delete ports; if (m_ports) delete m_ports;
ports = NULL; m_ports = NULL;
} }
QVector<QString>* SerialLink::getCurrentPorts() QVector<QString>* SerialLink::getCurrentPorts()
{ {
ports->clear(); Q_ASSERT_X(m_ports != NULL, "getCurrentPorts", "m_ports is NULL");
#ifdef __linux m_ports->clear();
// Example use QSerialPortInfo
// TODO Linux has no standard way of enumerating serial ports foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
// However the device files are only present when the physical
// device is connected, therefore listing the files should be
// sufficient.
QString devdir = "/dev";
QDir dir(devdir);
dir.setFilter(QDir::System);
QFileInfoList list = dir.entryInfoList();
for (int i = 0; i < list.size(); ++i) {
QFileInfo fileInfo = list.at(i);
if (fileInfo.fileName().contains(QString("ttyUSB")) || fileInfo.fileName().contains(QString("ttyS")) || fileInfo.fileName().contains(QString("ttyACM")))
{
ports->append(fileInfo.canonicalFilePath());
}
}
#endif
#if defined (__APPLE__) && defined (__MACH__)
// Enumerate serial ports
kern_return_t kernResult; // on PowerPC this is an int (4 bytes)
io_iterator_t serialPortIterator;
char bsdPath[MAXPATHLEN];
kernResult = FindModems(&serialPortIterator);
kernResult = GetModemPath(serialPortIterator, bsdPath, sizeof(bsdPath));
IOObjectRelease(serialPortIterator); // Release the iterator.
// Add found modems
if (bsdPath[0])
{ {
ports->append(QString(bsdPath)); // qDebug() << "PortName : " << info.portName()
} // << "Description : " << info.description();
// qDebug() << "Manufacturer: " << info.manufacturer();
// Add USB serial port adapters m_ports->append(info.portName());
// TODO Strangely usb serial port adapters are not enumerated, even when connected
QString devdir = "/dev";
QDir dir(devdir);
dir.setFilter(QDir::System);
QFileInfoList list = dir.entryInfoList();
for (int i = list.size() - 1; i >= 0; i--) {
QFileInfo fileInfo = list.at(i);
if (fileInfo.fileName().contains(QString("ttyUSB")) ||
fileInfo.fileName().contains(QString("tty.")) ||
fileInfo.fileName().contains(QString("ttyS")) ||
fileInfo.fileName().contains(QString("ttyACM")))
{
ports->append(fileInfo.canonicalFilePath());
}
} }
#endif return m_ports;
#ifdef _WIN32
// Get the ports available on this system
QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
// Add the ports in reverse order, because we prepend them to the list
for (int i = ports.size() - 1; i >= 0; i--)
{
QextPortInfo portInfo = ports.at(i);
QString portString = QString(portInfo.portName.toLocal8Bit().constData());// + " - " + QString(ports.at(i).friendName.toLocal8Bit().constData()).split("(").first();
// Prepend newly found port to the list
this->ports->append(portString);
}
//printf("port name: %s\n", ports.at(i).portName.toLocal8Bit().constData());
//printf("friendly name: %s\n", ports.at(i).friendName.toLocal8Bit().constData());
//printf("physical name: %s\n", ports.at(i).physName.toLocal8Bit().constData());
//printf("enumerator name: %s\n", ports.at(i).enumName.toLocal8Bit().constData());
//printf("===================================\n\n");
#endif
return this->ports;
} }
void SerialLink::loadSettings() void SerialLink::loadSettings()
...@@ -369,12 +109,12 @@ void SerialLink::loadSettings() ...@@ -369,12 +109,12 @@ void SerialLink::loadSettings()
settings.sync(); settings.sync();
if (settings.contains("SERIALLINK_COMM_PORT")) if (settings.contains("SERIALLINK_COMM_PORT"))
{ {
setPortName(settings.value("SERIALLINK_COMM_PORT").toString()); m_portName = settings.value("SERIALLINK_COMM_PORT").toString();
setBaudRateType(settings.value("SERIALLINK_COMM_BAUD").toInt()); m_baud = settings.value("SERIALLINK_COMM_BAUD").toInt();
setParityType(settings.value("SERIALLINK_COMM_PARITY").toInt()); m_parity = settings.value("SERIALLINK_COMM_PARITY").toInt();
setStopBits(settings.value("SERIALLINK_COMM_STOPBITS").toInt()); m_stopBits = settings.value("SERIALLINK_COMM_STOPBITS").toInt();
setDataBits(settings.value("SERIALLINK_COMM_DATABITS").toInt()); m_dataBits = settings.value("SERIALLINK_COMM_DATABITS").toInt();
setFlowType(settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt()); m_flowControl = settings.value("SERIALLINK_COMM_FLOW_CONTROL").toInt();
} }
} }
...@@ -402,18 +142,19 @@ void SerialLink::run() ...@@ -402,18 +142,19 @@ void SerialLink::run()
if (!hardwareConnect()) if (!hardwareConnect())
{ {
//Need to error out here. //Need to error out here.
emit communicationError(getName(),"Error connecting: " + port->errorString()); emit communicationError(getName(),"Error connecting: " + m_port->errorString());
return; return;
} }
// Qt way to make clear what a while(1) loop does // Qt way to make clear what a while(1) loop does
quint64 msecs = QDateTime::currentMSecsSinceEpoch(); qint64 msecs = QDateTime::currentMSecsSinceEpoch();
quint64 initialmsecs = QDateTime::currentMSecsSinceEpoch(); qint64 initialmsecs = QDateTime::currentMSecsSinceEpoch();
quint64 bytes = 0; quint64 bytes = 0;
bool triedreset = false; bool triedreset = false;
bool triedDTR = false; bool triedDTR = false;
int timeout = 5000; qint64 timeout = 5000;
forever forever
{ {
{ {
...@@ -427,16 +168,16 @@ void SerialLink::run() ...@@ -427,16 +168,16 @@ void SerialLink::run()
{ {
this->m_reqReset = false; this->m_reqReset = false;
communicationUpdate(getName(),"Reset requested via DTR signal"); communicationUpdate(getName(),"Reset requested via DTR signal");
port->setDtr(true); m_port->setDataTerminalReady(true);
this->msleep(250); this->msleep(250);
port->setDtr(false); m_port->setDataTerminalReady(false);
} }
} }
// Check if new bytes have arrived, if yes, emit the notification signal // Check if new bytes have arrived, if yes, emit the notification signal
checkForBytes(); checkForBytes();
if (bytes != bytesRead) if (bytes != m_bytesRead)
{ {
bytes = bytesRead; bytes = m_bytesRead;
msecs = QDateTime::currentMSecsSinceEpoch(); msecs = QDateTime::currentMSecsSinceEpoch();
} }
else else
...@@ -459,15 +200,15 @@ void SerialLink::run() ...@@ -459,15 +200,15 @@ void SerialLink::run()
triedDTR = true; triedDTR = true;
communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal"); communicationUpdate(getName(),"No data to receive on COM port. Attempting to reset via DTR signal");
qDebug() << "No data!!! Attempting reset via DTR."; qDebug() << "No data!!! Attempting reset via DTR.";
port->setDtr(true); m_port->setDataTerminalReady(true);
this->msleep(250); this->msleep(250);
port->setDtr(false); m_port->setDataTerminalReady(false);
} }
else if (!triedreset) else if (!triedreset)
{ {
qDebug() << "No data!!! Attempting reset via reboot command."; qDebug() << "No data!!! Attempting reset via reboot command.";
communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command"); communicationUpdate(getName(),"No data to receive on COM port. Assuming possible terminal mode, attempting to reset via \"reboot\" command");
port->write("reboot\r\n",8); m_port->write("reboot\r\n",8);
triedreset = true; triedreset = true;
} }
else else
...@@ -481,13 +222,12 @@ void SerialLink::run() ...@@ -481,13 +222,12 @@ void SerialLink::run()
* from consuming too much processing time * from consuming too much processing time
*/ */
MG::SLEEP::msleep(SerialLink::poll_interval); MG::SLEEP::msleep(SerialLink::poll_interval);
} } // end forever loop
if (port) {
port->flushInBuffer(); if (m_port) {
port->flushOutBuffer(); m_port->close();
port->close(); delete m_port;
delete port; m_port = NULL;
port = NULL;
} }
} }
...@@ -495,23 +235,23 @@ void SerialLink::run() ...@@ -495,23 +235,23 @@ void SerialLink::run()
void SerialLink::checkForBytes() void SerialLink::checkForBytes()
{ {
/* Check if bytes are available */ /* Check if bytes are available */
if(port && port->isOpen() && port->isWritable()) if(m_port && m_port->isOpen() && m_port->isWritable())
{ {
dataMutex.lock(); m_dataMutex.lock();
qint64 available = port->bytesAvailable(); qint64 available = m_port->bytesAvailable();
dataMutex.unlock(); m_dataMutex.unlock();
if(available > 0) if(available > 0)
{ {
readBytes(); readBytes();
bytesRead += available; m_bytesRead += available;
} }
else if (available < 0) { else if (available < 0) {
/* Error, close port */ /* Error, close port */
port->close(); m_port->close();
emit disconnected(); emit disconnected();
emit connected(false); emit connected(false);
emit communicationError(this->getName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); emit communicationError(this->getName(), tr("Could not read data - link %1 is disconnected!").arg(this->getName()));
} }
} }
// else // else
...@@ -524,27 +264,26 @@ void SerialLink::checkForBytes() ...@@ -524,27 +264,26 @@ void SerialLink::checkForBytes()
void SerialLink::writeBytes(const char* data, qint64 size) void SerialLink::writeBytes(const char* data, qint64 size)
{ {
if(port && port->isOpen()) { if(m_port && m_port->isOpen()) {
int b = port->write(data, size); qDebug() << "writeBytes" << m_portName << "attempting to tx " << size << "bytes.";
int b = m_port->write(data, size);
if (b > 0) { if (b > 0) {
Q_ASSERT_X(b = size, "writeBytes", "failed to write all bytes");
// qDebug() << "Serial link " << this->getName() << "transmitted" << b << "bytes:"; qDebug() << "writeBytes " << m_portName << "tx'd" << b << "bytes:";
// Increase write counter // Increase write counter
bitsSentTotal += size * 8; m_bitsSentTotal += size * 8;
QByteArray* byteArray = new QByteArray(data,size);
qDebug() << byteArray->toHex();
delete byteArray;
// int i;
// for (i=0; i<size; i++)
// {
// unsigned char v =data[i];
// qDebug("%02x ", v);
// }
// qDebug("\n");
} else { } else {
disconnect(); disconnect();
// Error occured // Error occured
emit communicationError(this->getName(), tr("Could not send data - link %1 is disconnected!").arg(this->getName())); emit communicationError(getName(), tr("Could not send data - link %1 is disconnected!").arg(getName()));
} }
} }
} }
...@@ -557,18 +296,18 @@ void SerialLink::writeBytes(const char* data, qint64 size) ...@@ -557,18 +296,18 @@ void SerialLink::writeBytes(const char* data, qint64 size)
**/ **/
void SerialLink::readBytes() void SerialLink::readBytes()
{ {
dataMutex.lock(); m_dataMutex.lock();
if(port && port->isOpen()) { if(m_port && m_port->isOpen()) {
const qint64 maxLength = 2048; const qint64 maxLength = 2048;
char data[maxLength]; char data[maxLength];
qint64 numBytes = port->bytesAvailable(); qint64 numBytes = m_port->bytesAvailable();
//qDebug() << "numBytes: " << numBytes; //qDebug() << "numBytes: " << numBytes;
if(numBytes > 0) { if(numBytes > 0) {
/* Read as much data in buffer as possible without overflow */ /* Read as much data in buffer as possible without overflow */
if(maxLength < numBytes) numBytes = maxLength; if(maxLength < numBytes) numBytes = maxLength;
port->read(data, numBytes); m_port->read(data, numBytes);
QByteArray b(data, numBytes); QByteArray b(data, numBytes);
emit bytesReceived(this, b); emit bytesReceived(this, b);
...@@ -580,10 +319,10 @@ void SerialLink::readBytes() ...@@ -580,10 +319,10 @@ void SerialLink::readBytes()
// fprintf(stderr,"%02x ", v); // fprintf(stderr,"%02x ", v);
// } // }
// fprintf(stderr,"\n"); // fprintf(stderr,"\n");
bitsReceivedTotal += numBytes * 8; m_bitsReceivedTotal += numBytes * 8;
} }
} }
dataMutex.unlock(); m_dataMutex.unlock();
} }
...@@ -594,8 +333,8 @@ void SerialLink::readBytes() ...@@ -594,8 +333,8 @@ void SerialLink::readBytes()
**/ **/
qint64 SerialLink::bytesAvailable() qint64 SerialLink::bytesAvailable()
{ {
if (port) { if (m_port) {
return port->bytesAvailable(); return m_port->bytesAvailable();
} else { } else {
return 0; return 0;
} }
...@@ -608,44 +347,24 @@ qint64 SerialLink::bytesAvailable() ...@@ -608,44 +347,24 @@ qint64 SerialLink::bytesAvailable()
**/ **/
bool SerialLink::disconnect() bool SerialLink::disconnect()
{ {
if(this->isRunning()) qDebug() << "disconnect" << m_port->portName();
Q_ASSERT_X(m_port != NULL, "disconnect", "m_port is NULL");
if (isRunning())
{ {
{ {
QMutexLocker locker(&this->m_stoppMutex); QMutexLocker locker(&m_stoppMutex);
this->m_stopp = true; m_stopp = true;
} }
this->wait(); wait(); // This will terminate the thread and close the serial port
// if (port) {
//#if !defined _WIN32 || !defined _WIN64
/* Block the thread until it returns from run() */
//#endif
// port->flushInBuffer();
// port->flushOutBuffer();
// port->close();
// delete port;
// port = NULL;
// if(this->isRunning()) this->terminate(); //stop running the thread, restart it upon connect
bool closed = true;
//port->isOpen();
emit disconnected(); emit disconnected(); // [TODO] There are signals from QSerialPort we should use
emit connected(false); emit connected(false);
if (port) { return true;
port->close(); } else {
} m_port->close();
return closed;
}
else {
// not running
if (port) {
port->close();
}
return true; return true;
} }
} }
/** /**
...@@ -655,12 +374,14 @@ bool SerialLink::disconnect() ...@@ -655,12 +374,14 @@ bool SerialLink::disconnect()
**/ **/
bool SerialLink::connect() bool SerialLink::connect()
{ {
if (this->isRunning()) this->disconnect(); if (isRunning())
disconnect();
{ {
QMutexLocker locker(&this->m_stoppMutex); QMutexLocker locker(&this->m_stoppMutex);
this->m_stopp = false; m_stopp = false;
} }
this->start(LowPriority);
start(LowPriority);
return true; return true;
} }
...@@ -674,36 +395,52 @@ bool SerialLink::connect() ...@@ -674,36 +395,52 @@ bool SerialLink::connect()
**/ **/
bool SerialLink::hardwareConnect() bool SerialLink::hardwareConnect()
{ {
if(port) { if(m_port)
port->close(); {
delete port; qDebug() << "SerialLink:" << QString::number((long)this, 16) << "closing port";
m_port->close();
delete m_port;
m_port = NULL;
} }
port = new QSerialPort(porthandle, portSettings); qDebug() << "SerialLink: hardwareConnect to " << m_portName;
QObject::connect(port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected())); m_port = new QSerialPort(m_portName);
port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);
connectionStartTime = MG::TIME::getGroundTimeNow();
if (!port->open()) if (m_port == NULL)
{ {
emit communicationUpdate(getName(),"Error opening port: " + port->errorString()); emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
return false; // couldn't create serial port.
} }
else
QObject::connect(m_port,SIGNAL(aboutToClose()),this,SIGNAL(disconnected()));
// port->setCommTimeouts(QSerialPort::CtScheme_NonBlockingRead);
m_connectionStartTime = MG::TIME::getGroundTimeNow();
if (!m_port->open(QIODevice::ReadWrite))
{ {
emit communicationUpdate(getName(),"Opened port!"); emit communicationUpdate(getName(),"Error opening port: " + m_port->errorString());
m_port->close();
return false; // couldn't open serial port
} }
bool connectionUp = isConnected(); emit communicationUpdate(getName(),"Opened port!");
if(connectionUp) {
emit connected();
emit connected(true);
}
//qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << port->portName() << getBaudRate() << getDataBits() << getParityType() << getStopBits(); // Need to configure the port
m_port->setBaudRate(m_baud);
m_port->setDataBits(static_cast<QSerialPort::DataBits>(m_dataBits));
m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(m_flowControl));
m_port->setStopBits(static_cast<QSerialPort::StopBits>(m_stopBits));
m_port->setParity(static_cast<QSerialPort::Parity>(m_parity));
emit connected();
emit connected(true);
qDebug() << "CONNECTING LINK: " << __FILE__ << __LINE__ << "with settings" << m_port->portName()
<< getBaudRate() << getDataBits() << getParityType() << getStopBits();
writeSettings(); writeSettings();
return connectionUp; return true; // successful connection
} }
...@@ -714,138 +451,82 @@ bool SerialLink::hardwareConnect() ...@@ -714,138 +451,82 @@ bool SerialLink::hardwareConnect()
**/ **/
bool SerialLink::isConnected() bool SerialLink::isConnected()
{ {
if (port) {
return port->isOpen(); if (m_port) {
bool isConnected = m_port->isOpen();
qDebug() << "SerialLink #" << __LINE__ << ":"<< m_port->portName()
<< " isConnected =" << QString::number(isConnected);
return isConnected;
} else { } else {
qDebug() << "SerialLink #" << __LINE__ << ":" << m_portName
<< " isConnected = NULL";
return false; return false;
} }
} }
int SerialLink::getId() int SerialLink::getId()
{ {
return id; return m_id;
} }
QString SerialLink::getName() QString SerialLink::getName()
{ {
return name; return m_name;
}
void SerialLink::setName(QString name)
{
this->name = name;
emit nameChanged(this->name);
} }
/** /**
* This function maps baud rate constants to numerical equivalents. * This function maps baud rate constants to numerical equivalents.
* It relies on the mapping given in qportsettings.h from the QSerialPort library. * It relies on the mapping given in qportsettings.h from the QSerialPort library.
*/ */
qint64 SerialLink::getNominalDataRate() qint64 SerialLink::getNominalDataRate()
{ {
qint64 dataRate = 0; int baudRate;
switch (portSettings.baudRate()) { if (m_port) {
baudRate = m_port->baudRate();
// Baud rates supported only by POSIX systems } else {
#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) baudRate = m_baud;
case QPortSettings::BAUDR_50: }
dataRate = 50; qint64 dataRate;
break; switch (baudRate)
case QPortSettings::BAUDR_75: {
dataRate = 75; case QSerialPort::Baud1200:
break; dataRate = 1200;
case QPortSettings::BAUDR_134: break;
dataRate = 134; case QSerialPort::Baud2400:
break; dataRate = 2400;
case QPortSettings::BAUDR_150: break;
dataRate = 150; case QSerialPort::Baud4800:
break; dataRate = 4800;
case QPortSettings::BAUDR_200: break;
dataRate = 200; case QSerialPort::Baud9600:
break; dataRate = 9600;
case QPortSettings::BAUDR_1800: break;
dataRate = 1800; case QSerialPort::Baud19200:
break; dataRate = 19200;
#endif break;
case QSerialPort::Baud38400:
// Baud rates supported only by Windows dataRate = 38400;
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) break;
case QPortSettings::BAUDR_14400: case QSerialPort::Baud57600:
dataRate = 14400; dataRate = 57600;
break; break;
case QPortSettings::BAUDR_56000: case QSerialPort::Baud115200:
dataRate = 56000; dataRate = 115200;
break; break;
case QPortSettings::BAUDR_128000: // Otherwise do nothing.
dataRate = 128000; case QSerialPort::UnknownBaud:
break; default:
case QPortSettings::BAUDR_256000: dataRate = -1;
dataRate = 256000; break;
#endif
case QPortSettings::BAUDR_110:
dataRate = 110;
break;
case QPortSettings::BAUDR_300:
dataRate = 300;
break;
case QPortSettings::BAUDR_600:
dataRate = 600;
break;
case QPortSettings::BAUDR_1200:
dataRate = 1200;
break;
case QPortSettings::BAUDR_2400:
dataRate = 2400;
break;
case QPortSettings::BAUDR_4800:
dataRate = 4800;
break;
case QPortSettings::BAUDR_9600:
dataRate = 9600;
break;
case QPortSettings::BAUDR_19200:
dataRate = 19200;
break;
case QPortSettings::BAUDR_38400:
dataRate = 38400;
break;
case QPortSettings::BAUDR_57600:
dataRate = 57600;
break;
case QPortSettings::BAUDR_115200:
dataRate = 115200;
break;
case QPortSettings::BAUDR_230400:
dataRate = 230400;
break;
case QPortSettings::BAUDR_460800:
dataRate = 460800;
break;
case QPortSettings::BAUDR_500000:
dataRate = 500000;
break;
case QPortSettings::BAUDR_576000:
dataRate = 576000;
break;
case QPortSettings::BAUDR_921600:
dataRate = 921600;
break;
// Otherwise do nothing.
case QPortSettings::BAUDR_UNKNOWN:
default:
break;
} }
return dataRate; return dataRate;
} }
qint64 SerialLink::getTotalUpstream() qint64 SerialLink::getTotalUpstream()
{ {
statisticsMutex.lock(); m_statisticsMutex.lock();
return bitsSentTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); return m_bitsSentTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
statisticsMutex.unlock(); m_statisticsMutex.unlock();
} }
qint64 SerialLink::getCurrentUpstream() qint64 SerialLink::getCurrentUpstream()
...@@ -860,19 +541,19 @@ qint64 SerialLink::getMaxUpstream() ...@@ -860,19 +541,19 @@ qint64 SerialLink::getMaxUpstream()
qint64 SerialLink::getBitsSent() qint64 SerialLink::getBitsSent()
{ {
return bitsSentTotal; return m_bitsSentTotal;
} }
qint64 SerialLink::getBitsReceived() qint64 SerialLink::getBitsReceived()
{ {
return bitsReceivedTotal; return m_bitsReceivedTotal;
} }
qint64 SerialLink::getTotalDownstream() qint64 SerialLink::getTotalDownstream()
{ {
statisticsMutex.lock(); m_statisticsMutex.lock();
return bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - connectionStartTime) / 1000); return m_bitsReceivedTotal / ((MG::TIME::getGroundTimeNow() - m_connectionStartTime) / 1000);
statisticsMutex.unlock(); m_statisticsMutex.unlock();
} }
qint64 SerialLink::getCurrentDownstream() qint64 SerialLink::getCurrentDownstream()
...@@ -899,9 +580,11 @@ int SerialLink::getLinkQuality() ...@@ -899,9 +580,11 @@ int SerialLink::getLinkQuality()
QString SerialLink::getPortName() QString SerialLink::getPortName()
{ {
return porthandle; return m_portName;
} }
// We should replace the accessors below with one to get the QSerialPort
int SerialLink::getBaudRate() int SerialLink::getBaudRate()
{ {
return getNominalDataRate(); return getNominalDataRate();
...@@ -909,43 +592,80 @@ int SerialLink::getBaudRate() ...@@ -909,43 +592,80 @@ int SerialLink::getBaudRate()
int SerialLink::getBaudRateType() int SerialLink::getBaudRateType()
{ {
return portSettings.baudRate(); int baudRate;
if (m_port) {
baudRate = m_port->baudRate();
} else {
baudRate = m_baud;
}
return baudRate;
} }
int SerialLink::getFlowType() int SerialLink::getFlowType()
{ {
return portSettings.flowControl(); int flowControl;
if (m_port) {
flowControl = m_port->flowControl();
} else {
flowControl = m_flowControl;
}
return flowControl;
} }
int SerialLink::getParityType() int SerialLink::getParityType()
{ {
return portSettings.parity(); int parity;
if (m_port) {
parity = m_port->parity();
} else {
parity = m_parity;
}
return parity;
} }
int SerialLink::getDataBitsType() int SerialLink::getDataBitsType()
{ {
return portSettings.dataBits(); int dataBits;
if (m_port) {
dataBits = m_port->dataBits();
} else {
dataBits = m_dataBits;
}
return dataBits;
} }
int SerialLink::getStopBitsType() int SerialLink::getStopBitsType()
{ {
return portSettings.stopBits(); int stopBits;
if (m_port) {
stopBits = m_port->stopBits();
} else {
stopBits = m_stopBits;
}
return stopBits;
} }
int SerialLink::getDataBits() int SerialLink::getDataBits()
{ {
int ret = -1; int ret;
switch (portSettings.dataBits()) { int dataBits;
case QPortSettings::DB_5: if (m_port) {
dataBits = m_port->dataBits();
} else {
dataBits = m_dataBits;
}
switch (dataBits) {
case QSerialPort::Data5:
ret = 5; ret = 5;
break; break;
case QPortSettings::DB_6: case QSerialPort::Data6:
ret = 6; ret = 6;
break; break;
case QPortSettings::DB_7: case QSerialPort::Data7:
ret = 7; ret = 7;
break; break;
case QPortSettings::DB_8: case QSerialPort::Data8:
ret = 8; ret = 8;
break; break;
default: default:
...@@ -957,12 +677,18 @@ int SerialLink::getDataBits() ...@@ -957,12 +677,18 @@ int SerialLink::getDataBits()
int SerialLink::getStopBits() int SerialLink::getStopBits()
{ {
int stopBits;
if (m_port) {
stopBits = m_port->stopBits();
} else {
stopBits = m_stopBits;
}
int ret = -1; int ret = -1;
switch (portSettings.stopBits()) { switch (stopBits) {
case QPortSettings::STOP_1: case QSerialPort::OneStop:
ret = 1; ret = 1;
break; break;
case QPortSettings::STOP_2: case QSerialPort::TwoStop:
ret = 2; ret = 2;
break; break;
default: default:
...@@ -974,56 +700,36 @@ int SerialLink::getStopBits() ...@@ -974,56 +700,36 @@ int SerialLink::getStopBits()
bool SerialLink::setPortName(QString portName) bool SerialLink::setPortName(QString portName)
{ {
if(portName.trimmed().length() > 0) { qDebug() << "current portName " << m_portName;
bool reconnect = false; qDebug() << "setPortName to " << portName;
if (isConnected()) reconnect = true; bool accepted = false;
disconnect(); if ((portName != m_portName)
&& (portName.trimmed().length() > 0)) {
this->porthandle = portName.trimmed(); m_portName = portName.trimmed();
setName(tr("serial port ") + portName.trimmed()); m_name = tr("serial port ") + portName.trimmed(); // [TODO] Do we need this?
#ifdef _WIN32 if(m_port)
// Port names above 20 need the network path format - if the port name is not already in this format m_port->setPortName(portName);
// catch this special case
if (!this->porthandle.startsWith("\\")) {
// Append \\.\ before the port handle. Additional backslashes are used for escaping.
this->porthandle = "\\\\.\\" + this->porthandle;
}
#endif
if(reconnect) connect(); emit nameChanged(m_name); // [TODO] maybe we can eliminate this
return true; return accepted;
} else {
return false;
} }
return false;
} }
bool SerialLink::setBaudRateType(int rateIndex) bool SerialLink::setBaudRateType(int rateIndex)
{ {
bool reconnect = false; Q_ASSERT_X(m_port != NULL, "setBaudRateType", "m_port is NULL");
bool accepted = true; // This is changed if none of the data rates matches // These minimum and maximum baud rates were based on those enumerated in qserialport.h
if(isConnected()) reconnect = true; const int minBaud = (int)QSerialPort::Baud1200;
disconnect(); const int maxBaud = (int)QSerialPort::Baud115200;
// These minimum and maximum baud rates were based on those enumerated in qportsettings.h. if (m_port && (rateIndex >= minBaud && rateIndex <= maxBaud))
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
const int minBaud = (int)QPortSettings::BAUDR_110;
const int maxBaud = (int)QPortSettings::BAUDR_921600;
#elif defined(Q_OS_LINUX)
const int minBaud = (int)QPortSettings::BAUDR_50;
const int maxBaud = (int)QPortSettings::BAUDR_921600;
#elif defined(Q_OS_UNIX) || defined(Q_OS_DARWIN)
const int minBaud = (int)QPortSettings::BAUDR_50;
const int maxBaud = (int)QPortSettings::BAUDR_921600;
#endif
if (rateIndex >= minBaud && rateIndex <= maxBaud)
{ {
portSettings.setBaudRate((QPortSettings::BaudRate)rateIndex); return m_port->setBaudRate(static_cast<QSerialPort::BaudRate>(rateIndex));
} }
if(reconnect) connect(); return false;
return accepted;
} }
bool SerialLink::setBaudRateString(const QString& rate) bool SerialLink::setBaudRateString(const QString& rate)
...@@ -1036,260 +742,104 @@ bool SerialLink::setBaudRateString(const QString& rate) ...@@ -1036,260 +742,104 @@ bool SerialLink::setBaudRateString(const QString& rate)
bool SerialLink::setBaudRate(int rate) bool SerialLink::setBaudRate(int rate)
{ {
bool reconnect = false; bool accepted = false;
bool accepted = true; // This is changed if none of the data rates matches if (rate != m_baud) {
if(isConnected()) { m_baud = rate;
reconnect = true; accepted = true;
} if (m_port)
disconnect(); accepted = m_port->setBaudRate(rate);
// This switch-statment relies on the mapping given in qportsettings.h from the QSerialPort library.
switch (rate) {
// Baud rates supported only by non-Windows systems
#if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_DARWIN)
case 50:
portSettings.setBaudRate(QPortSettings::BAUDR_50);
break;
case 75:
portSettings.setBaudRate(QPortSettings::BAUDR_75);
break;
case 134:
portSettings.setBaudRate(QPortSettings::BAUDR_134);
break;
case 150:
portSettings.setBaudRate(QPortSettings::BAUDR_150);
break;
case 200:
portSettings.setBaudRate(QPortSettings::BAUDR_200);
break;
case 1800:
portSettings.setBaudRate(QPortSettings::BAUDR_1800);
break;
#endif
// Baud rates supported only by windows
#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
case 14400:
portSettings.setBaudRate(QPortSettings::BAUDR_14400);
break;
case 56000:
portSettings.setBaudRate(QPortSettings::BAUDR_56000);
break;
case 128000:
portSettings.setBaudRate(QPortSettings::BAUDR_128000);
break;
case 256000:
portSettings.setBaudRate(QPortSettings::BAUDR_256000);
break;
#endif
// Supported by all OSes:
case 110:
portSettings.setBaudRate(QPortSettings::BAUDR_110);
break;
case 300:
portSettings.setBaudRate(QPortSettings::BAUDR_300);
break;
case 600:
portSettings.setBaudRate(QPortSettings::BAUDR_600);
break;
case 1200:
portSettings.setBaudRate(QPortSettings::BAUDR_1200);
break;
case 2400:
portSettings.setBaudRate(QPortSettings::BAUDR_2400);
break;
case 4800:
portSettings.setBaudRate(QPortSettings::BAUDR_4800);
break;
case 9600:
portSettings.setBaudRate(QPortSettings::BAUDR_9600);
break;
case 19200:
portSettings.setBaudRate(QPortSettings::BAUDR_19200);
break;
case 38400:
portSettings.setBaudRate(QPortSettings::BAUDR_38400);
break;
case 57600:
portSettings.setBaudRate(QPortSettings::BAUDR_57600);
break;
case 115200:
portSettings.setBaudRate(QPortSettings::BAUDR_115200);
break;
case 230400:
portSettings.setBaudRate(QPortSettings::BAUDR_230400);
break;
case 460800:
portSettings.setBaudRate(QPortSettings::BAUDR_460800);
break;
case 500000:
portSettings.setBaudRate(QPortSettings::BAUDR_500000);
break;
case 576000:
portSettings.setBaudRate(QPortSettings::BAUDR_576000);
break;
case 921600:
portSettings.setBaudRate(QPortSettings::BAUDR_921600);
break;
default:
// If none of the above cases matches, there must be an error
accepted = false;
break;
} }
if(reconnect) connect();
return accepted; return accepted;
} }
bool SerialLink::setFlowType(int flow) bool SerialLink::setFlowType(int flow)
{ {
bool reconnect = false; bool accepted = false;
bool accepted = true; if (flow != m_flowControl) {
if(isConnected()) reconnect = true; m_flowControl = static_cast<QSerialPort::FlowControl>(flow);
disconnect(); accepted = true;
if (m_port)
switch (flow) { accepted = m_port->setFlowControl(static_cast<QSerialPort::FlowControl>(flow));
case (int)QPortSettings::FLOW_OFF:
portSettings.setFlowControl(QPortSettings::FLOW_OFF);
break;
case (int)QPortSettings::FLOW_HARDWARE:
portSettings.setFlowControl(QPortSettings::FLOW_HARDWARE);
break;
case (int)QPortSettings::FLOW_XONXOFF:
portSettings.setFlowControl(QPortSettings::FLOW_XONXOFF);
break;
default:
// If none of the above cases matches, there must be an error
accepted = false;
break;
} }
if(reconnect) connect();
return accepted; return accepted;
} }
bool SerialLink::setParityType(int parity) bool SerialLink::setParityType(int parity)
{ {
bool reconnect = false; bool accepted = false;
bool accepted = true; if (parity != m_parity) {
if (isConnected()) reconnect = true; m_parity = static_cast<QSerialPort::Parity>(parity);
disconnect(); accepted = true;
if (m_port) {
switch (parity) { switch (parity) {
case (int)QPortSettings::PAR_NONE: case QSerialPort::NoParity:
portSettings.setParity(QPortSettings::PAR_NONE); accepted = m_port->setParity(QSerialPort::NoParity);
break; break;
case (int)QPortSettings::PAR_ODD: case 1: // Odd Parity setting for backwards compatibilty
portSettings.setParity(QPortSettings::PAR_ODD); accepted = m_port->setParity(QSerialPort::OddParity);
break; break;
case (int)QPortSettings::PAR_EVEN: case QSerialPort::EvenParity:
portSettings.setParity(QPortSettings::PAR_EVEN); accepted = m_port->setParity(QSerialPort::EvenParity);
break; break;
case (int)QPortSettings::PAR_SPACE: case QSerialPort::OddParity:
portSettings.setParity(QPortSettings::PAR_SPACE); accepted = m_port->setParity(QSerialPort::OddParity);
break; break;
default: default:
// If none of the above cases matches, there must be an error // If none of the above cases matches, there must be an error
accepted = false; accepted = false;
break; break;
}
}
} }
if (reconnect) connect();
return accepted; return accepted;
} }
bool SerialLink::setDataBits(int dataBits) bool SerialLink::setDataBits(int dataBits)
{ {
//qDebug() << "Setting" << dataBits << "data bits"; bool accepted = false;
bool reconnect = false; if (dataBits != m_dataBits) {
if (isConnected()) reconnect = true; m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
bool accepted = true; accepted = true;
disconnect(); if (m_port)
accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
switch (dataBits) {
case 5:
portSettings.setDataBits(QPortSettings::DB_5);
break;
case 6:
portSettings.setDataBits(QPortSettings::DB_6);
break;
case 7:
portSettings.setDataBits(QPortSettings::DB_7);
break;
case 8:
portSettings.setDataBits(QPortSettings::DB_8);
break;
default:
// If none of the above cases matches, there must be an error
accepted = false;
break;
} }
if(reconnect) connect();
return accepted; return accepted;
} }
bool SerialLink::setStopBits(int stopBits) bool SerialLink::setStopBits(int stopBits)
{ {
bool reconnect = false; // Note 3 is OneAndAHalf stopbits.
bool accepted = true; bool accepted = false;
if(isConnected()) reconnect = true; if (stopBits != m_stopBits) {
disconnect(); m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
accepted = true;
switch (stopBits) { if (m_port)
case 1: accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
portSettings.setStopBits(QPortSettings::STOP_1);
break;
case 2:
portSettings.setStopBits(QPortSettings::STOP_2);
break;
default:
// If none of the above cases matches, there must be an error
accepted = false;
break;
} }
if(reconnect) connect();
return accepted; return accepted;
} }
bool SerialLink::setDataBitsType(int dataBits) bool SerialLink::setDataBitsType(int dataBits)
{ {
bool reconnect = false;
bool accepted = false; bool accepted = false;
if (dataBits != m_dataBits) {
if (isConnected()) reconnect = true; m_dataBits = static_cast<QSerialPort::DataBits>(dataBits);
disconnect();
if (dataBits >= (int)QPortSettings::DB_5 && dataBits <= (int)QPortSettings::DB_8) {
portSettings.setDataBits((QPortSettings::DataBits) dataBits);
if(reconnect) connect();
accepted = true; accepted = true;
if (m_port)
accepted = m_port->setDataBits(static_cast<QSerialPort::DataBits>(dataBits));
} }
return accepted; return accepted;
} }
bool SerialLink::setStopBitsType(int stopBits) bool SerialLink::setStopBitsType(int stopBits)
{ {
bool reconnect = false;
bool accepted = false; bool accepted = false;
if(isConnected()) reconnect = true; if (stopBits != m_stopBits) {
disconnect(); m_stopBits = static_cast<QSerialPort::StopBits>(stopBits);
if (stopBits >= (int)QPortSettings::STOP_1 && stopBits <= (int)QPortSettings::STOP_2) {
portSettings.setStopBits((QPortSettings::StopBits) stopBits);
if(reconnect) connect();
accepted = true; accepted = true;
if (m_port)
accepted = m_port->setStopBits(static_cast<QSerialPort::StopBits>(stopBits));
} }
if(reconnect) connect();
return accepted; return accepted;
} }
...@@ -36,13 +36,9 @@ This file is part of the QGROUNDCONTROL project ...@@ -36,13 +36,9 @@ This file is part of the QGROUNDCONTROL project
#include <QThread> #include <QThread>
#include <QMutex> #include <QMutex>
#include <QString> #include <QString>
#include "qserialport.h" #include <qserialport.h>
#include <configuration.h> #include <configuration.h>
#include "SerialLinkInterface.h" #include "SerialLinkInterface.h"
#ifdef _WIN32
#include "windows.h"
#endif
/** /**
* @brief The SerialLink class provides cross-platform access to serial links. * @brief The SerialLink class provides cross-platform access to serial links.
...@@ -146,37 +142,36 @@ protected slots: ...@@ -146,37 +142,36 @@ protected slots:
void checkForBytes(); void checkForBytes();
protected: protected:
quint64 bytesRead; quint64 m_bytesRead;
TNX::QSerialPort * port; QSerialPort* m_port;
TNX::QPortSettings portSettings; int m_baud;
#ifdef _WIN32 int m_dataBits;
HANDLE winPort; int m_flowControl;
DCB winPortSettings; int m_stopBits;
#endif int m_parity;
QString porthandle; QString m_portName;
QString name; QString m_name;
int timeout; int m_timeout;
int id; int m_id;
quint64 bitsSentTotal; quint64 m_bitsSentTotal;
quint64 bitsSentShortTerm; quint64 m_bitsSentShortTerm;
quint64 bitsSentCurrent; quint64 m_bitsSentCurrent;
quint64 bitsSentMax; quint64 m_bitsSentMax;
quint64 bitsReceivedTotal; quint64 m_bitsReceivedTotal;
quint64 bitsReceivedShortTerm; quint64 m_bitsReceivedShortTerm;
quint64 bitsReceivedCurrent; quint64 m_bitsReceivedCurrent;
quint64 bitsReceivedMax; quint64 m_bitsReceivedMax;
quint64 connectionStartTime; quint64 m_connectionStartTime;
QMutex statisticsMutex; QMutex m_statisticsMutex;
QMutex dataMutex; QMutex m_dataMutex;
QVector<QString>* ports; QVector<QString>* m_ports;
private: private:
volatile bool m_stopp; volatile bool m_stopp;
volatile bool m_reqReset; volatile bool m_reqReset;
QMutex m_stoppMutex; QMutex m_stoppMutex;
void setName(QString name);
bool hardwareConnect(); bool hardwareConnect();
signals: signals:
......
...@@ -259,7 +259,7 @@ void SerialConfigurationWindow::setParityNone(bool accept) ...@@ -259,7 +259,7 @@ void SerialConfigurationWindow::setParityNone(bool accept)
void SerialConfigurationWindow::setParityOdd(bool accept) void SerialConfigurationWindow::setParityOdd(bool accept)
{ {
if (accept) link->setParityType(1); if (accept) link->setParityType(1); // [TODO] This needs to be Fixed [BB]
} }
void SerialConfigurationWindow::setParityEven(bool accept) void SerialConfigurationWindow::setParityEven(bool accept)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment