summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2015-09-07 20:22:40 +0300
committerDenis Shienkov <denis.shienkov@gmail.com>2015-09-08 18:38:21 +0000
commit77a97c7650252366d4027580d0d5e13daa9e33ce (patch)
tree4469ee775683e858caf8dfab76e6e00bef303827
parent841adec3d196f6dde50ff89585483950493ac113 (diff)
downloadqtserialport-77a97c7650252366d4027580d0d5e13daa9e33ce.tar.gz
Get rid of stored termios structure
It is better to read the current termios structure each time before changing, than to have stored it locally. Tested with the USB serial ports. (cherry-picked from 23aedbb75bd6bb187756dc96157c49d79637362c) Change-Id: I63e0c2c1c320ee4b98c8423963d78396f72eb3c2 Reviewed-by: Denis Shienkov <denis.shienkov@gmail.com>
-rw-r--r--src/serialport/qserialport_unix.cpp175
-rw-r--r--src/serialport/qserialport_unix_p.h4
2 files changed, 110 insertions, 69 deletions
diff --git a/src/serialport/qserialport_unix.cpp b/src/serialport/qserialport_unix.cpp
index 024f05b..b6194d0 100644
--- a/src/serialport/qserialport_unix.cpp
+++ b/src/serialport/qserialport_unix.cpp
@@ -443,17 +443,21 @@ bool QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Direc
}
#endif
- if ((directions & QSerialPort::Input) && ::cfsetispeed(&currentTermios, baudRate) < 0) {
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
+ if ((directions & QSerialPort::Input) && ::cfsetispeed(&tio, baudRate) < 0) {
setError(getSystemError());
return false;
}
- if ((directions & QSerialPort::Output) && ::cfsetospeed(&currentTermios, baudRate) < 0) {
+ if ((directions & QSerialPort::Output) && ::cfsetospeed(&tio, baudRate) < 0) {
setError(getSystemError());
return false;
}
- return updateTermios();
+ return setTermios(&tio);
}
#if defined(Q_OS_LINUX)
@@ -552,105 +556,125 @@ bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions di
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
- currentTermios.c_cflag &= ~CSIZE;
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
+ tio.c_cflag &= ~CSIZE;
switch (dataBits) {
case QSerialPort::Data5:
- currentTermios.c_cflag |= CS5;
+ tio.c_cflag |= CS5;
break;
case QSerialPort::Data6:
- currentTermios.c_cflag |= CS6;
+ tio.c_cflag |= CS6;
break;
case QSerialPort::Data7:
- currentTermios.c_cflag |= CS7;
+ tio.c_cflag |= CS7;
break;
case QSerialPort::Data8:
- currentTermios.c_cflag |= CS8;
+ tio.c_cflag |= CS8;
break;
default:
- currentTermios.c_cflag |= CS8;
+ tio.c_cflag |= CS8;
break;
}
- return updateTermios();
+ return setTermios(&tio);
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
- currentTermios.c_iflag &= ~(PARMRK | INPCK);
- currentTermios.c_iflag |= IGNPAR;
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
+ 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:
- currentTermios.c_cflag &= ~PARODD;
- currentTermios.c_cflag |= PARENB | CMSPAR;
+ tio.c_cflag &= ~PARODD;
+ tio.c_cflag |= PARENB | CMSPAR;
break;
case QSerialPort::MarkParity:
- currentTermios.c_cflag |= PARENB | CMSPAR | PARODD;
+ tio.c_cflag |= PARENB | CMSPAR | PARODD;
break;
#endif
case QSerialPort::NoParity:
- currentTermios.c_cflag &= ~PARENB;
+ tio.c_cflag &= ~PARENB;
break;
case QSerialPort::EvenParity:
- currentTermios.c_cflag &= ~PARODD;
- currentTermios.c_cflag |= PARENB;
+ tio.c_cflag &= ~PARODD;
+ tio.c_cflag |= PARENB;
break;
case QSerialPort::OddParity:
- currentTermios.c_cflag |= PARENB | PARODD;
+ tio.c_cflag |= PARENB | PARODD;
break;
default:
- currentTermios.c_cflag |= PARENB;
- currentTermios.c_iflag |= PARMRK | INPCK;
- currentTermios.c_iflag &= ~IGNPAR;
+ tio.c_cflag |= PARENB;
+ tio.c_iflag |= PARMRK | INPCK;
+ tio.c_iflag &= ~IGNPAR;
break;
}
- return updateTermios();
+ return setTermios(&tio);
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
switch (stopBits) {
case QSerialPort::OneStop:
- currentTermios.c_cflag &= ~CSTOPB;
+ tio.c_cflag &= ~CSTOPB;
break;
case QSerialPort::TwoStop:
- currentTermios.c_cflag |= CSTOPB;
+ tio.c_cflag |= CSTOPB;
break;
default:
- currentTermios.c_cflag &= ~CSTOPB;
+ tio.c_cflag &= ~CSTOPB;
break;
}
- return updateTermios();
+ return setTermios(&tio);
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
{
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
switch (flowControl) {
case QSerialPort::NoFlowControl:
- currentTermios.c_cflag &= ~CRTSCTS;
- currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ tio.c_cflag &= ~CRTSCTS;
+ tio.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case QSerialPort::HardwareControl:
- currentTermios.c_cflag |= CRTSCTS;
- currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ tio.c_cflag |= CRTSCTS;
+ tio.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case QSerialPort::SoftwareControl:
- currentTermios.c_cflag &= ~CRTSCTS;
- currentTermios.c_iflag |= IXON | IXOFF | IXANY;
+ tio.c_cflag &= ~CRTSCTS;
+ tio.c_iflag |= IXON | IXOFF | IXANY;
break;
default:
- currentTermios.c_cflag &= ~CRTSCTS;
- currentTermios.c_iflag &= ~(IXON | IXOFF | IXANY);
+ tio.c_cflag &= ~CRTSCTS;
+ tio.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
}
- return updateTermios();
+ return setTermios(&tio);
}
bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
{
+ termios tio;
+ if (!getTermios(&tio))
+ return false;
+
tcflag_t parmrkMask = PARMRK;
#ifndef CMSPAR
// in space/mark parity emulation also used PARMRK flag
@@ -661,25 +685,25 @@ bool QSerialPortPrivate::setDataErrorPolicy(QSerialPort::DataErrorPolicy policy)
#endif //CMSPAR
switch (policy) {
case QSerialPort::SkipPolicy:
- currentTermios.c_iflag &= ~parmrkMask;
- currentTermios.c_iflag |= IGNPAR | INPCK;
+ tio.c_iflag &= ~parmrkMask;
+ tio.c_iflag |= IGNPAR | INPCK;
break;
case QSerialPort::PassZeroPolicy:
- currentTermios.c_iflag &= ~(IGNPAR | parmrkMask);
- currentTermios.c_iflag |= INPCK;
+ tio.c_iflag &= ~(IGNPAR | parmrkMask);
+ tio.c_iflag |= INPCK;
break;
case QSerialPort::IgnorePolicy:
- currentTermios.c_iflag &= ~INPCK;
+ tio.c_iflag &= ~INPCK;
break;
case QSerialPort::StopReceivingPolicy:
- currentTermios.c_iflag &= ~IGNPAR;
- currentTermios.c_iflag |= parmrkMask | INPCK;
+ tio.c_iflag &= ~IGNPAR;
+ tio.c_iflag |= parmrkMask | INPCK;
break;
default:
- currentTermios.c_iflag &= ~INPCK;
+ tio.c_iflag &= ~INPCK;
break;
}
- return updateTermios();
+ return setTermios(&tio);
}
bool QSerialPortPrivate::readNotification()
@@ -787,29 +811,28 @@ inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
setError(getSystemError());
#endif
- if (::tcgetattr(descriptor, &restoredTermios) == -1) {
- setError(getSystemError());
+ termios tio;
+ if (!getTermios(&tio))
return false;
- }
- currentTermios = restoredTermios;
+ restoredTermios = tio;
#ifdef Q_OS_SOLARIS
- currentTermios.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
- currentTermios.c_oflag &= ~OPOST;
- currentTermios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- currentTermios.c_cflag &= ~(CSIZE|PARENB);
- currentTermios.c_cflag |= CS8;
+ 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(&currentTermios);
+ ::cfmakeraw(&tio);
#endif
- currentTermios.c_cflag |= CLOCAL;
- currentTermios.c_cc[VTIME] = 0;
- currentTermios.c_cc[VMIN] = 0;
+ tio.c_cflag |= CLOCAL;
+ tio.c_cc[VTIME] = 0;
+ tio.c_cc[VMIN] = 0;
if (mode & QIODevice::ReadOnly)
- currentTermios.c_cflag |= CREAD;
+ tio.c_cflag |= CREAD;
- if (!updateTermios())
+ if (!setTermios(&tio))
return false;
if (mode & QIODevice::ReadOnly)
@@ -826,9 +849,19 @@ qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
return maxSize;
}
-bool QSerialPortPrivate::updateTermios()
+bool QSerialPortPrivate::setTermios(const termios *tio)
{
- if (::tcsetattr(descriptor, TCSANOW, &currentTermios) == -1) {
+ if (::tcsetattr(descriptor, TCSANOW, tio) == -1) {
+ setError(getSystemError());
+ return false;
+ }
+ return true;
+}
+
+bool QSerialPortPrivate::getTermios(termios *tio)
+{
+ ::memset(tio, 0, sizeof(termios));
+ if (::tcgetattr(descriptor, tio) == -1) {
setError(getSystemError());
return false;
}
@@ -1016,6 +1049,10 @@ static inline bool evenParity(quint8 c)
qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
{
+ termios tio;
+ if (!getTermios(&tio))
+ return -1;
+
qint64 ret = 0;
quint8 const charMask = (0xFF >> (8 - dataBits));
@@ -1024,11 +1061,11 @@ qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 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
+ 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 (!updateTermios())
+ if (!setTermios(&tio))
break;
}
@@ -1047,6 +1084,10 @@ qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize)
{
+ termios tio;
+ if (!getTermios(&tio))
+ return -1;
+
qint64 ret = 0;
quint8 const charMask = (0xFF >> (8 - dataBits));
@@ -1087,7 +1128,7 @@ qint64 QSerialPortPrivate::readPerChar(char *data, qint64 maxSize)
}
// 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
+ par ^= (tio.c_cflag & PARODD); //par contains parity bit value for current mode
if (par ^ (parity == QSerialPort::SpaceParity)) { //if parity error
switch (policy) {
case QSerialPort::SkipPolicy:
diff --git a/src/serialport/qserialport_unix_p.h b/src/serialport/qserialport_unix_p.h
index 353592b..ad74b17 100644
--- a/src/serialport/qserialport_unix_p.h
+++ b/src/serialport/qserialport_unix_p.h
@@ -146,7 +146,6 @@ public:
static QList<qint32> standardBaudRates();
- struct termios currentTermios;
struct termios restoredTermios;
int descriptor;
@@ -163,7 +162,8 @@ public:
private:
bool initialize(QIODevice::OpenMode mode);
- bool updateTermios();
+ bool setTermios(const termios *tio);
+ bool getTermios(termios *tio);
bool setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions);
bool setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions);