Qt Serial Port Baud Rate

I need to be able to change the baud rate on the port without the DTR or RTS lines changing. It works in the SimpleIDE 0-8-5 terminal. There is a baud-rate box in the terminal that can be changed at any time.

Permalink

Join GitHub today

GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.

Sign up
Branch:master
Find file Copy path
Cannot retrieve contributors at this time
/****************************************************************************
**
** 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: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include'qserialport_p.h'
#include'qserialportinfo_p.h'
#include<QtCore/qelapsedtimer.h>
#include<QtCore/qmap.h>
#include<QtCore/qsocketnotifier.h>
#include<QtCore/qstandardpaths.h>
#include<private/qcore_unix_p.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include<sys/time.h>
#include<unistd.h>
#ifdef Q_OS_OSX
#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
#ifdef Q_OS_QNX
#defineCRTSCTS (IHFLOW OHFLOW)
#endif
#ifdef Q_OS_LINUX
# ifdef Q_OS_ANDROID
# include<android/api-level.h>
# else
# define__ANDROID_API__21
# endif
# if !defined(Q_OS_ANDROID) (!defined(Q_PROCESSOR_X86) && __ANDROID_API__ < 21)
structtermios2 {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[19]; /* control characters */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
};
# endif
#ifndef TCGETS2
#defineTCGETS2_IOR('T', 0x2A, structtermios2)
#endif
#ifndef TCSETS2
#defineTCSETS2_IOW('T', 0x2B, structtermios2)
#endif
#ifndef BOTHER
#defineBOTHER0010000
#endif
#endif
QT_BEGIN_NAMESPACE
QString serialPortLockFilePath(const QString &portName)
{
staticconst QStringList lockDirectoryPaths = QStringList()
<< QStringLiteral('/var/lock')
<< QStringLiteral('/etc/locks')
<< QStringLiteral('/var/spool/locks')
<< QStringLiteral('/var/spool/uucp')
<< QStringLiteral('/tmp')
<< QStringLiteral('/var/tmp')
<< QStringLiteral('/var/lock/lockdev')
<< QStringLiteral('/run/lock')
#ifdef Q_OS_ANDROID
<< QStringLiteral('/data/local/tmp')
#endif
<< QStandardPaths::writableLocation(QStandardPaths::TempLocation);
QString fileName = portName;
fileName.replace(QLatin1Char('/'), QLatin1Char('_'));
fileName.prepend(QLatin1String('/LCK..'));
QString lockFilePath;
for (const QString &lockDirectoryPath : lockDirectoryPaths) {
const QString filePath = lockDirectoryPath + fileName;
QFileInfo lockDirectoryInfo(lockDirectoryPath);
if (lockDirectoryInfo.isReadable()) {
if (QFile::exists(filePath) lockDirectoryInfo.isWritable()) {
lockFilePath = filePath;
break;
}
}
}
if (lockFilePath.isEmpty()) {
qWarning('The following directories are not readable or writable for detaling with lock filesn');
for (const QString &lockDirectoryPath : lockDirectoryPaths)
qWarning('t%sn', qPrintable(lockDirectoryPath));
returnQString();
}
return lockFilePath;
}
classReadNotifier : publicQSocketNotifier
{
public:
explicitReadNotifier(QSerialPortPrivate *d, QObject *parent)
: QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
, dptr(d)
{
}
protected:
boolevent(QEvent *e) Q_DECL_OVERRIDE
{
if (e->type() QEvent::SockAct) {
dptr->readNotification();
returntrue;
}
returnQSocketNotifier::event(e);
}
private:
QSerialPortPrivate * const dptr;
};
classWriteNotifier : publicQSocketNotifier
{
public:
explicitWriteNotifier(QSerialPortPrivate *d, QObject *parent)
: QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
, dptr(d)
{
}
protected:
boolevent(QEvent *e) Q_DECL_OVERRIDE
{
if (e->type() QEvent::SockAct) {
dptr->completeAsyncWrite();
returntrue;
}
returnQSocketNotifier::event(e);
}
private:
QSerialPortPrivate * const dptr;
};
staticinlinevoidqt_set_common_props(termios *tio, QIODevice::OpenMode m)
{
#ifdef Q_OS_SOLARIS
tio->c_iflag &= ~(IMAXBEL IGNBRK BRKINT PARMRK ISTRIP INLCR IGNCR ICRNL IXON);
tio->c_oflag &= ~OPOST;
tio->c_lflag &= ~(ECHO ECHONL ICANON ISIG IEXTEN);
tio->c_cflag &= ~(CSIZE PARENB);
tio->c_cflag = CS8;
#else
::cfmakeraw(tio);
#endif
tio->c_cflag = CLOCAL;
tio->c_cc[VTIME] = 0;
tio->c_cc[VMIN] = 0;
if (m & QIODevice::ReadOnly)
tio->c_cflag = CREAD;
}
staticinlinevoidqt_set_databits(termios *tio, QSerialPort::DataBits databits)
{
tio->c_cflag &= ~CSIZE;
switch (databits) {
case QSerialPort::Data5:
tio->c_cflag = CS5;
break;
case QSerialPort::Data6:
tio->c_cflag = CS6;
break;
case QSerialPort::Data7:
tio->c_cflag = CS7;
break;
case QSerialPort::Data8:
tio->c_cflag = CS8;
break;
default:
tio->c_cflag = CS8;
break;
}
}
staticinlinevoidqt_set_parity(termios *tio, QSerialPort::Parity parity)
{
tio->c_iflag &= ~(PARMRK INPCK);
tio->c_iflag = IGNPAR;
switch (parity) {
#ifdef CMSPAR
// Here Installation parity only for GNU/Linux where the macro CMSPAR.
case QSerialPort::SpaceParity:
tio->c_cflag &= ~PARODD;
tio->c_cflag = PARENB CMSPAR;
break;
case QSerialPort::MarkParity:
tio->c_cflag = PARENB CMSPAR PARODD;
break;
#endif
case QSerialPort::NoParity:
tio->c_cflag &= ~PARENB;
break;
case QSerialPort::EvenParity:
tio->c_cflag &= ~PARODD;
tio->c_cflag = PARENB;
break;
case QSerialPort::OddParity:
tio->c_cflag = PARENB PARODD;
break;
default:
tio->c_cflag = PARENB;
tio->c_iflag = PARMRK INPCK;
tio->c_iflag &= ~IGNPAR;
break;
}
}
staticinlinevoidqt_set_stopbits(termios *tio, QSerialPort::StopBits stopbits)
{
switch (stopbits) {
case QSerialPort::OneStop:
tio->c_cflag &= ~CSTOPB;
break;
case QSerialPort::TwoStop:
tio->c_cflag = CSTOPB;
break;
default:
tio->c_cflag &= ~CSTOPB;
break;
}
}
staticinlinevoidqt_set_flowcontrol(termios *tio, QSerialPort::FlowControl flowcontrol)
{
switch (flowcontrol) {
case QSerialPort::NoFlowControl:
tio->c_cflag &= ~CRTSCTS;
tio->c_iflag &= ~(IXON IXOFF IXANY);
break;
case QSerialPort::HardwareControl:
tio->c_cflag = CRTSCTS;
tio->c_iflag &= ~(IXON IXOFF IXANY);
break;
case QSerialPort::SoftwareControl:
tio->c_cflag &= ~CRTSCTS;
tio->c_iflag = IXON IXOFF IXANY;
break;
default:
tio->c_cflag &= ~CRTSCTS;
tio->c_iflag &= ~(IXON IXOFF IXANY);
break;
}
}
boolQSerialPortPrivate::open(QIODevice::OpenMode mode)
{
QString lockFilePath = serialPortLockFilePath(QSerialPortInfoPrivate::portNameFromSystemLocation(systemLocation));
bool isLockFileEmpty = lockFilePath.isEmpty();
if (isLockFileEmpty) {
qWarning('Failed to create a lock file for opening the device');
setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr('Permission error while creating lock file')));
returnfalse;
}
QScopedPointer<QLockFile> newLockFileScopedPointer(newQLockFile(lockFilePath));
if (!newLockFileScopedPointer->tryLock()) {
setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr('Permission error while locking the device')));
returnfalse;
}
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 = qt_safe_open(systemLocation.toLocal8Bit().constData(), flags);
if (descriptor -1) {
setError(getSystemError());
returnfalse;
}
if (!initialize(mode)) {
qt_safe_close(descriptor);
returnfalse;
}
lockFileScopedPointer.swap(newLockFileScopedPointer);
returntrue;
}
voidQSerialPortPrivate::close()
{
if (settingsRestoredOnClose)
::tcsetattr(descriptor, TCSANOW, &restoredTermios);
#ifdef TIOCNXCL
::ioctl(descriptor, TIOCNXCL);
#endif
delete readNotifier;
readNotifier = nullptr;
delete writeNotifier;
writeNotifier = nullptr;
qt_safe_close(descriptor);
lockFileScopedPointer.reset(nullptr);
descriptor = -1;
pendingBytesWritten = 0;
writeSequenceStarted = false;
}
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
{
int arg = 0;
if (::ioctl(descriptor, TIOCMGET, &arg) -1) {
setError(getSystemError());
return QSerialPort::NoSignal;
}
QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
#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;
}
boolQSerialPortPrivate::setDataTerminalReady(bool set)
{
int status = TIOCM_DTR;
if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::setRequestToSend(bool set)
{
int status = TIOCM_RTS;
if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::flush()
{
returncompleteAsyncWrite();
}
boolQSerialPortPrivate::clear(QSerialPort::Directions directions)
{
if (::tcflush(descriptor, (directions QSerialPort::AllDirections)
? TCIOFLUSH : (directions & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::sendBreak(int duration)
{
if (::tcsendbreak(descriptor, duration) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::setBreakEnabled(bool set)
{
if (::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::waitForReadyRead(int msecs)
{
QElapsedTimer stopWatch;
stopWatch.start();
do {
bool readyToRead = false;
bool readyToWrite = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
returnfalse;
}
if (readyToRead)
returnreadNotification();
if (readyToWrite && !completeAsyncWrite())
returnfalse;
} while (msecs -1qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
returnfalse;
}
boolQSerialPortPrivate::waitForBytesWritten(int msecs)
{
if (writeBuffer.isEmpty() && pendingBytesWritten <= 0)
returnfalse;
QElapsedTimer stopWatch;
stopWatch.start();
for (;;) {
bool readyToRead = false;
bool readyToWrite = false;
if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
returnfalse;
}
if (readyToRead && !readNotification())
returnfalse;
if (readyToWrite)
returncompleteAsyncWrite();
}
returnfalse;
}
boolQSerialPortPrivate::setBaudRate()
{
if (inputBaudRate outputBaudRate)
returnsetBaudRate(inputBaudRate, QSerialPort::AllDirections);
return (setBaudRate(inputBaudRate, QSerialPort::Input)
&& setBaudRate(outputBaudRate, QSerialPort::Output));
}
boolQSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
#ifdef Q_OS_LINUX
// try to clear custom baud rate, using termios v2
structtermios2 tio2;
if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
if (tio2.c_cflag & BOTHER) {
tio2.c_cflag &= ~BOTHER;
tio2.c_cflag = CBAUD;
::ioctl(descriptor, TCSETS2, &tio2);
}
}
// try to clear custom baud rate, using serial_struct (old way)
structserial_struct serial;
::memset(&serial, 0, sizeof(serial));
if (::ioctl(descriptor, TIOCGSERIAL, &serial) != -1) {
if (serial.flags & ASYNC_SPD_CUST) {
serial.flags &= ~ASYNC_SPD_CUST;
serial.custom_divisor = 0;
// we don't check on errors because a driver can has not this feature
::ioctl(descriptor, TIOCSSERIAL, &serial);
}
}
#endif
termios tio;
if (!getTermios(&tio))
returnfalse;
if ((directions & QSerialPort::Input) && ::cfsetispeed(&tio, baudRate) < 0) {
setError(getSystemError());
returnfalse;
}
if ((directions & QSerialPort::Output) && ::cfsetospeed(&tio, baudRate) < 0) {
setError(getSystemError());
returnfalse;
}
returnsetTermios(&tio);
}
#if defined(Q_OS_LINUX)
boolQSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
if (directions != QSerialPort::AllDirections) {
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
QSerialPort::tr('Cannot set custom speed for one direction')));
returnfalse;
}
structtermios2 tio2;
if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
tio2.c_cflag &= ~CBAUD;
tio2.c_cflag = BOTHER;
tio2.c_ispeed = baudRate;
tio2.c_ospeed = baudRate;
if (::ioctl(descriptor, TCSETS2, &tio2) != -1
&& ::ioctl(descriptor, TCGETS2, &tio2) != -1) {
returntrue;
}
}
structserial_struct serial;
if (::ioctl(descriptor, TIOCGSERIAL, &serial) -1) {
setError(getSystemError());
returnfalse;
}
serial.flags &= ~ASYNC_SPD_MASK;
serial.flags = (ASYNC_SPD_CUST /* ASYNC_LOW_LATENCY*/);
serial.custom_divisor = serial.baud_base / baudRate;
if (serial.custom_divisor0) {
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
QSerialPort::tr('No suitable custom baud rate divisor')));
returnfalse;
}
if (serial.custom_divisor * baudRate != serial.baud_base) {
qWarning('Baud rate of serial port %s is set to %f instead of %d: divisor %f unsupported',
qPrintable(systemLocation),
float(serial.baud_base) / serial.custom_divisor,
baudRate, float(serial.baud_base) / baudRate);
}
if (::ioctl(descriptor, TIOCSSERIAL, &serial) -1) {
setError(getSystemError());
returnfalse;
}
returnsetStandardBaudRate(B38400, directions);
}
#elif defined(Q_OS_OSX)
boolQSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
if (directions != QSerialPort::AllDirections) {
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
QSerialPort::tr('Cannot set custom speed for one direction')));
returnfalse;
}
#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
#else
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
QSerialPort::tr('Custom baud rate is not supported')));
returnfalse;
#endif
}
#elif defined(Q_OS_QNX)
boolQSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
// On QNX, the values of the 'Bxxxx' constants are set to 'xxxx' (i.e.
// B115200 is defined to '115200'), which means that literal values can be
// passed to cfsetispeed/cfsetospeed, including custom values, provided
// that the underlying hardware supports them.
returnsetStandardBaudRate(baudRate, directions);
}
#else
boolQSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
Q_UNUSED(baudRate);
Q_UNUSED(directions);
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
QSerialPort::tr('Custom baud rate is not supported')));
returnfalse;
}
#endif
boolQSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
if (baudRate <= 0) {
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr('Invalid baud rate value')));
returnfalse;
}
const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate);
return (unixBaudRate > 0)
? setStandardBaudRate(unixBaudRate, directions)
: setCustomBaudRate(baudRate, directions);
}
boolQSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
termios tio;
if (!getTermios(&tio))
returnfalse;
qt_set_databits(&tio, dataBits);
returnsetTermios(&tio);
}
boolQSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
termios tio;
if (!getTermios(&tio))
returnfalse;
qt_set_parity(&tio, parity);
returnsetTermios(&tio);
}
boolQSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
termios tio;
if (!getTermios(&tio))
returnfalse;
qt_set_stopbits(&tio, stopBits);
returnsetTermios(&tio);
}
boolQSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
{
termios tio;
if (!getTermios(&tio))
returnfalse;
qt_set_flowcontrol(&tio, flowControl);
returnsetTermios(&tio);
}
boolQSerialPortPrivate::startAsyncRead()
{
setReadNotificationEnabled(true);
returntrue;
}
boolQSerialPortPrivate::readNotification()
{
Q_Q(QSerialPort);
// Always buffered, read data from the port into the read buffer
qint64 newBytes = buffer.size();
qint64 bytesToRead = QSERIALPORT_BUFFERSIZE;
if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - buffer.size())) {
bytesToRead = readBufferMaxSize - buffer.size();
if (bytesToRead <= 0) {
// Buffer is full. User must read data from the buffer
// before we can read more from the port.
setReadNotificationEnabled(false);
returnfalse;
}
}
char *ptr = buffer.reserve(bytesToRead);
const qint64 readBytes = readFromPort(ptr, bytesToRead);
buffer.chop(bytesToRead - qMax(readBytes, qint64(0)));
if (readBytes <= 0) {
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::ResourceError)
error.errorCode = QSerialPort::ReadError;
else
setReadNotificationEnabled(false);
setError(error);
returnfalse;
}
newBytes = buffer.size() - newBytes;
// only emit readyRead() when not recursing, and only if there is data available
constbool hasData = newBytes > 0;
if (!emittedReadyRead && hasData) {
emittedReadyRead = true;
emit q->readyRead();
emittedReadyRead = false;
}
returntrue;
}
boolQSerialPortPrivate::startAsyncWrite()
{
if (writeBuffer.isEmpty() writeSequenceStarted)
returntrue;
// Attempt to write it all in one chunk.
qint64 written = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize());
if (written < 0) {
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::ResourceError)
error.errorCode = QSerialPort::WriteError;
setError(error);
returnfalse;
}
writeBuffer.free(written);
pendingBytesWritten += written;
writeSequenceStarted = true;
if (!isWriteNotificationEnabled())
setWriteNotificationEnabled(true);
returntrue;
}
boolQSerialPortPrivate::completeAsyncWrite()
{
Q_Q(QSerialPort);
if (pendingBytesWritten > 0) {
if (!emittedBytesWritten) {
emittedBytesWritten = true;
emit q->bytesWritten(pendingBytesWritten);
pendingBytesWritten = 0;
emittedBytesWritten = false;
}
}
writeSequenceStarted = false;
if (writeBuffer.isEmpty()) {
setWriteNotificationEnabled(false);
returntrue;
}
returnstartAsyncWrite();
}
inlineboolQSerialPortPrivate::initialize(QIODevice::OpenMode mode)
{
#ifdef TIOCEXCL
if (::ioctl(descriptor, TIOCEXCL) -1)
setError(getSystemError());
#endif
termios tio;
if (!getTermios(&tio))
returnfalse;
restoredTermios = tio;
qt_set_common_props(&tio, mode);
qt_set_databits(&tio, dataBits);
qt_set_parity(&tio, parity);
qt_set_stopbits(&tio, stopBits);
qt_set_flowcontrol(&tio, flowControl);
if (!setTermios(&tio))
returnfalse;
if (!setBaudRate())
returnfalse;
if (mode & QIODevice::ReadOnly)
setReadNotificationEnabled(true);
returntrue;
}
qint64 QSerialPortPrivate::writeData(constchar *data, qint64 maxSize)
{
writeBuffer.append(data, maxSize);
if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
setWriteNotificationEnabled(true);
return maxSize;
}
boolQSerialPortPrivate::setTermios(const termios *tio)
{
if (::tcsetattr(descriptor, TCSANOW, tio) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
boolQSerialPortPrivate::getTermios(termios *tio)
{
::memset(tio, 0, sizeof(termios));
if (::tcgetattr(descriptor, tio) -1) {
setError(getSystemError());
returnfalse;
}
returntrue;
}
QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
{
if (systemErrorCode -1)
systemErrorCode = errno;
QSerialPortErrorInfo error;
error.errorString = qt_error_string(systemErrorCode);
switch (systemErrorCode) {
case ENODEV:
error.errorCode = QSerialPort::DeviceNotFoundError;
break;
#ifdef ENOENT
case ENOENT:
error.errorCode = QSerialPort::DeviceNotFoundError;
break;
#endif
case EACCES:
error.errorCode = QSerialPort::PermissionError;
break;
case EBUSY:
error.errorCode = QSerialPort::PermissionError;
break;
case EAGAIN:
error.errorCode = QSerialPort::ResourceError;
break;
case EIO:
error.errorCode = QSerialPort::ResourceError;
break;
case EBADF:
error.errorCode = QSerialPort::ResourceError;
break;
#ifdef Q_OS_OSX
case ENXIO:
error.errorCode = QSerialPort::ResourceError;
break;
#endif
#ifdef EINVAL
case EINVAL:
error.errorCode = QSerialPort::UnsupportedOperationError;
break;
#endif
#ifdef ENOIOCTLCMD
case ENOIOCTLCMD:
error.errorCode = QSerialPort::UnsupportedOperationError;
break;
#endif
#ifdef ENOTTY
case ENOTTY:
error.errorCode = QSerialPort::UnsupportedOperationError;
break;
#endif
#ifdef EPERM
case EPERM:
error.errorCode = QSerialPort::PermissionError;
break;
#endif
default:
error.errorCode = QSerialPort::UnknownError;
break;
}
return error;
}
boolQSerialPortPrivate::isReadNotificationEnabled() const
{
return readNotifier && readNotifier->isEnabled();
}
voidQSerialPortPrivate::setReadNotificationEnabled(bool enable)
{
Q_Q(QSerialPort);
if (readNotifier) {
readNotifier->setEnabled(enable);
} elseif (enable) {
readNotifier = newReadNotifier(this, q);
readNotifier->setEnabled(true);
}
}
boolQSerialPortPrivate::isWriteNotificationEnabled() const
{
return writeNotifier && writeNotifier->isEnabled();
}
voidQSerialPortPrivate::setWriteNotificationEnabled(bool enable)
{
Q_Q(QSerialPort);
if (writeNotifier) {
writeNotifier->setEnabled(enable);
} elseif (enable) {
writeNotifier = newWriteNotifier(this, q);
writeNotifier->setEnabled(true);
}
}
boolQSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
bool checkRead, bool checkWrite,
int msecs)
{
Q_ASSERT(selectForRead);
Q_ASSERT(selectForWrite);
pollfd pfd = qt_make_pollfd(descriptor, 0);
if (checkRead)
pfd.events = POLLIN;
if (checkWrite)
pfd.events = POLLOUT;
constint ret = qt_poll_msecs(&pfd, 1, msecs);
if (ret < 0) {
setError(getSystemError());
returnfalse;
}
if (ret 0) {
setError(QSerialPortErrorInfo(QSerialPort::TimeoutError));
returnfalse;
}
if (pfd.revents & POLLNVAL) {
setError(getSystemError(EBADF));
returnfalse;
}
*selectForWrite = ((pfd.revents & POLLOUT) != 0);
*selectForRead = ((pfd.revents & POLLIN) != 0);
returntrue;
}
qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
{
returnqt_safe_read(descriptor, data, maxSize);
}
qint64 QSerialPortPrivate::writeToPort(constchar *data, qint64 maxSize)
{
qint64 bytesWritten = 0;
#if defined(CMSPAR)
bytesWritten = qt_safe_write(descriptor, data, maxSize);
#else
if (parity != QSerialPort::MarkParity
&& parity != QSerialPort::SpaceParity) {
bytesWritten = qt_safe_write(descriptor, data, maxSize);
} else {// Perform parity emulation.
bytesWritten = writePerChar(data, maxSize);
}
#endif
return bytesWritten;
}
#ifndef CMSPAR
staticinlineboolevenParity(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)
}
qint64 QSerialPortPrivate::writePerChar(constchar *data, qint64 maxSize)
{
termios tio;
if (!getTermios(&tio))
return -1;
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 ^ (tio.c_cflag & PARODD)) { // Need switch parity mode?
tio.c_cflag ^= PARODD;
flush(); //force sending already buffered data, because setTermios(&tio); cleares buffers
//todo: add receiving buffered data!!!
if (!setTermios(&tio))
break;
}
int r = qt_safe_write(descriptor, data, 1);
if (r < 0)
return -1;
if (r > 0) {
data += r;
ret += r;
}
}
return ret;
}
#endif//CMSPAR
typedef QMap<qint32, qint32> BaudRateMap;
// The OS specific defines can be found in termios.h
staticconst 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 B7200
baudRateMap.insert(7200, B7200);
#endif
#ifdef B9600
baudRateMap.insert(9600, B9600);
#endif
#ifdef B14400
baudRateMap.insert(14400, B14400);
#endif
#ifdef B19200
baudRateMap.insert(19200, B19200);
#endif
#ifdef B28800
baudRateMap.insert(28800, B28800);
#endif
#ifdef B38400
baudRateMap.insert(38400, B38400);
#endif
#ifdef B57600
baudRateMap.insert(57600, B57600);
#endif
#ifdef B76800
baudRateMap.insert(76800, B76800);
#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;
}
staticconst BaudRateMap& standardBaudRateMap()
{
staticconst BaudRateMap baudRateMap = createStandardBaudRateMap();
return baudRateMap;
}
qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
{
returnstandardBaudRateMap().value(baudRate);
}
QList<qint32> QSerialPortPrivate::standardBaudRates()
{
returnstandardBaudRateMap().keys();
}
QSerialPort::HandleQSerialPort::handle() const
{
Q_D(const QSerialPort);
return d->descriptor;
}
QT_END_NAMESPACE
  • Copy lines
  • Copy permalink