1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
4 ** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
5 ** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtSerialPort module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qserialport_p.h"
43 #include "qserialportinfo_p.h"
44
45 #include <QtCore/qelapsedtimer.h>
46 #include <QtCore/qmap.h>
47 #include <QtCore/qsocketnotifier.h>
48 #include <QtCore/qstandardpaths.h>
49
50 #include <private/qcore_unix_p.h>
51
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <sys/ioctl.h>
55 #include <sys/time.h>
56 #include <unistd.h>
57
58 #ifdef Q_OS_OSX
59 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
60 #include <IOKit/serial/ioss.h>
61 #endif
62 #endif
63
64 #ifdef Q_OS_QNX
65 #define CRTSCTS (IHFLOW | OHFLOW)
66 #endif
67
68 #ifdef Q_OS_LINUX
69
70 # ifdef Q_OS_ANDROID
71 # include <android/api-level.h>
72 # else
73 # define __ANDROID_API__ 16
74 # endif
75
76 # if !defined(Q_OS_ANDROID) || (!defined(Q_PROCESSOR_X86) && __ANDROID_API__ < 16)
77 struct termios2 {
78 tcflag_t c_iflag; /* input mode flags */
79 tcflag_t c_oflag; /* output mode flags */
80 tcflag_t c_cflag; /* control mode flags */
81 tcflag_t c_lflag; /* local mode flags */
82 cc_t c_line; /* line discipline */
83 cc_t c_cc[19]; /* control characters */
84 speed_t c_ispeed; /* input speed */
85 speed_t c_ospeed; /* output speed */
86 };
87 # endif
88
89 #ifndef TCGETS2
90 #define TCGETS2 _IOR('T', 0x2A, struct termios2)
91 #endif
92
93 #ifndef TCSETS2
94 #define TCSETS2 _IOW('T', 0x2B, struct termios2)
95 #endif
96
97 #ifndef BOTHER
98 #define BOTHER 0010000
99 #endif
100
101 #endif
102
103 QT_BEGIN_NAMESPACE
104
serialPortLockFilePath(const QString & portName)105 QString serialPortLockFilePath(const QString &portName)
106 {
107 static const QStringList lockDirectoryPaths = QStringList()
108 << QStringLiteral("/var/lock")
109 << QStringLiteral("/etc/locks")
110 << QStringLiteral("/var/spool/locks")
111 << QStringLiteral("/var/spool/uucp")
112 << QStringLiteral("/tmp")
113 << QStringLiteral("/var/tmp")
114 << QStringLiteral("/var/lock/lockdev")
115 << QStringLiteral("/run/lock")
116 #ifdef Q_OS_ANDROID
117 << QStringLiteral("/data/local/tmp")
118 #endif
119 << QStandardPaths::writableLocation(QStandardPaths::TempLocation);
120
121 QString fileName = portName;
122 fileName.replace(QLatin1Char('/'), QLatin1Char('_'));
123 fileName.prepend(QLatin1String("/LCK.."));
124
125 QString lockFilePath;
126
127 for (const QString &lockDirectoryPath : lockDirectoryPaths) {
128 const QString filePath = lockDirectoryPath + fileName;
129
130 QFileInfo lockDirectoryInfo(lockDirectoryPath);
131 if (lockDirectoryInfo.isReadable()) {
132 if (QFile::exists(filePath) || lockDirectoryInfo.isWritable()) {
133 lockFilePath = filePath;
134 break;
135 }
136 }
137 }
138
139 if (lockFilePath.isEmpty()) {
140 qWarning("The following directories are not readable or writable for detaling with lock files\n");
141 for (const QString &lockDirectoryPath : lockDirectoryPaths)
142 qWarning("\t%s\n", qPrintable(lockDirectoryPath));
143 return QString();
144 }
145
146 return lockFilePath;
147 }
148
149 class ReadNotifier : public QSocketNotifier
150 {
151 public:
ReadNotifier(QSerialPortPrivate * d,QObject * parent)152 explicit ReadNotifier(QSerialPortPrivate *d, QObject *parent)
153 : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
154 , dptr(d)
155 {
156 }
157
158 protected:
event(QEvent * e)159 bool event(QEvent *e) override
160 {
161 if (e->type() == QEvent::SockAct) {
162 dptr->readNotification();
163 return true;
164 }
165 return QSocketNotifier::event(e);
166 }
167
168 private:
169 QSerialPortPrivate * const dptr;
170 };
171
172 class WriteNotifier : public QSocketNotifier
173 {
174 public:
WriteNotifier(QSerialPortPrivate * d,QObject * parent)175 explicit WriteNotifier(QSerialPortPrivate *d, QObject *parent)
176 : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
177 , dptr(d)
178 {
179 }
180
181 protected:
event(QEvent * e)182 bool event(QEvent *e) override
183 {
184 if (e->type() == QEvent::SockAct) {
185 dptr->completeAsyncWrite();
186 return true;
187 }
188 return QSocketNotifier::event(e);
189 }
190
191 private:
192 QSerialPortPrivate * const dptr;
193 };
194
qt_set_common_props(termios * tio,QIODevice::OpenMode m)195 static inline void qt_set_common_props(termios *tio, QIODevice::OpenMode m)
196 {
197 #ifdef Q_OS_SOLARIS
198 tio->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
199 tio->c_oflag &= ~OPOST;
200 tio->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
201 tio->c_cflag &= ~(CSIZE|PARENB);
202 tio->c_cflag |= CS8;
203 #else
204 ::cfmakeraw(tio);
205 #endif
206
207 tio->c_cflag |= CLOCAL;
208 tio->c_cc[VTIME] = 0;
209 tio->c_cc[VMIN] = 0;
210
211 if (m & QIODevice::ReadOnly)
212 tio->c_cflag |= CREAD;
213 }
214
qt_set_databits(termios * tio,QSerialPort::DataBits databits)215 static inline void qt_set_databits(termios *tio, QSerialPort::DataBits databits)
216 {
217 tio->c_cflag &= ~CSIZE;
218 switch (databits) {
219 case QSerialPort::Data5:
220 tio->c_cflag |= CS5;
221 break;
222 case QSerialPort::Data6:
223 tio->c_cflag |= CS6;
224 break;
225 case QSerialPort::Data7:
226 tio->c_cflag |= CS7;
227 break;
228 case QSerialPort::Data8:
229 tio->c_cflag |= CS8;
230 break;
231 default:
232 tio->c_cflag |= CS8;
233 break;
234 }
235 }
236
qt_set_parity(termios * tio,QSerialPort::Parity parity)237 static inline void qt_set_parity(termios *tio, QSerialPort::Parity parity)
238 {
239 tio->c_iflag &= ~(PARMRK | INPCK);
240 tio->c_iflag |= IGNPAR;
241
242 switch (parity) {
243
244 #ifdef CMSPAR
245 // Here Installation parity only for GNU/Linux where the macro CMSPAR.
246 case QSerialPort::SpaceParity:
247 tio->c_cflag &= ~PARODD;
248 tio->c_cflag |= PARENB | CMSPAR;
249 break;
250 case QSerialPort::MarkParity:
251 tio->c_cflag |= PARENB | CMSPAR | PARODD;
252 break;
253 #endif
254 case QSerialPort::NoParity:
255 tio->c_cflag &= ~PARENB;
256 break;
257 case QSerialPort::EvenParity:
258 tio->c_cflag &= ~PARODD;
259 tio->c_cflag |= PARENB;
260 break;
261 case QSerialPort::OddParity:
262 tio->c_cflag |= PARENB | PARODD;
263 break;
264 default:
265 tio->c_cflag |= PARENB;
266 tio->c_iflag |= PARMRK | INPCK;
267 tio->c_iflag &= ~IGNPAR;
268 break;
269 }
270 }
271
qt_set_stopbits(termios * tio,QSerialPort::StopBits stopbits)272 static inline void qt_set_stopbits(termios *tio, QSerialPort::StopBits stopbits)
273 {
274 switch (stopbits) {
275 case QSerialPort::OneStop:
276 tio->c_cflag &= ~CSTOPB;
277 break;
278 case QSerialPort::TwoStop:
279 tio->c_cflag |= CSTOPB;
280 break;
281 default:
282 tio->c_cflag &= ~CSTOPB;
283 break;
284 }
285 }
286
qt_set_flowcontrol(termios * tio,QSerialPort::FlowControl flowcontrol)287 static inline void qt_set_flowcontrol(termios *tio, QSerialPort::FlowControl flowcontrol)
288 {
289 switch (flowcontrol) {
290 case QSerialPort::NoFlowControl:
291 tio->c_cflag &= ~CRTSCTS;
292 tio->c_iflag &= ~(IXON | IXOFF | IXANY);
293 break;
294 case QSerialPort::HardwareControl:
295 tio->c_cflag |= CRTSCTS;
296 tio->c_iflag &= ~(IXON | IXOFF | IXANY);
297 break;
298 case QSerialPort::SoftwareControl:
299 tio->c_cflag &= ~CRTSCTS;
300 tio->c_iflag |= IXON | IXOFF | IXANY;
301 break;
302 default:
303 tio->c_cflag &= ~CRTSCTS;
304 tio->c_iflag &= ~(IXON | IXOFF | IXANY);
305 break;
306 }
307 }
308
open(QIODevice::OpenMode mode)309 bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
310 {
311 QString lockFilePath = serialPortLockFilePath(QSerialPortInfoPrivate::portNameFromSystemLocation(systemLocation));
312 bool isLockFileEmpty = lockFilePath.isEmpty();
313 if (isLockFileEmpty) {
314 qWarning("Failed to create a lock file for opening the device");
315 setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while creating lock file")));
316 return false;
317 }
318
319 QScopedPointer<QLockFile> newLockFileScopedPointer(new QLockFile(lockFilePath));
320
321 if (!newLockFileScopedPointer->tryLock()) {
322 setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr("Permission error while locking the device")));
323 return false;
324 }
325
326 int flags = O_NOCTTY | O_NONBLOCK;
327
328 switch (mode & QIODevice::ReadWrite) {
329 case QIODevice::WriteOnly:
330 flags |= O_WRONLY;
331 break;
332 case QIODevice::ReadWrite:
333 flags |= O_RDWR;
334 break;
335 default:
336 flags |= O_RDONLY;
337 break;
338 }
339
340 descriptor = qt_safe_open(systemLocation.toLocal8Bit().constData(), flags);
341
342 if (descriptor == -1) {
343 setError(getSystemError());
344 return false;
345 }
346
347 if (!initialize(mode)) {
348 qt_safe_close(descriptor);
349 return false;
350 }
351
352 lockFileScopedPointer.swap(newLockFileScopedPointer);
353
354 return true;
355 }
356
close()357 void QSerialPortPrivate::close()
358 {
359 if (settingsRestoredOnClose)
360 ::tcsetattr(descriptor, TCSANOW, &restoredTermios);
361
362 #ifdef TIOCNXCL
363 ::ioctl(descriptor, TIOCNXCL);
364 #endif
365
366 delete readNotifier;
367 readNotifier = nullptr;
368
369 delete writeNotifier;
370 writeNotifier = nullptr;
371
372 qt_safe_close(descriptor);
373
374 lockFileScopedPointer.reset(nullptr);
375
376 descriptor = -1;
377 pendingBytesWritten = 0;
378 writeSequenceStarted = false;
379 }
380
pinoutSignals()381 QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
382 {
383 int arg = 0;
384
385 if (::ioctl(descriptor, TIOCMGET, &arg) == -1) {
386 setError(getSystemError());
387 return QSerialPort::NoSignal;
388 }
389
390 QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
391
392 #ifdef TIOCM_LE
393 if (arg & TIOCM_LE)
394 ret |= QSerialPort::DataSetReadySignal;
395 #endif
396 #ifdef TIOCM_DTR
397 if (arg & TIOCM_DTR)
398 ret |= QSerialPort::DataTerminalReadySignal;
399 #endif
400 #ifdef TIOCM_RTS
401 if (arg & TIOCM_RTS)
402 ret |= QSerialPort::RequestToSendSignal;
403 #endif
404 #ifdef TIOCM_ST
405 if (arg & TIOCM_ST)
406 ret |= QSerialPort::SecondaryTransmittedDataSignal;
407 #endif
408 #ifdef TIOCM_SR
409 if (arg & TIOCM_SR)
410 ret |= QSerialPort::SecondaryReceivedDataSignal;
411 #endif
412 #ifdef TIOCM_CTS
413 if (arg & TIOCM_CTS)
414 ret |= QSerialPort::ClearToSendSignal;
415 #endif
416 #ifdef TIOCM_CAR
417 if (arg & TIOCM_CAR)
418 ret |= QSerialPort::DataCarrierDetectSignal;
419 #elif defined(TIOCM_CD)
420 if (arg & TIOCM_CD)
421 ret |= QSerialPort::DataCarrierDetectSignal;
422 #endif
423 #ifdef TIOCM_RNG
424 if (arg & TIOCM_RNG)
425 ret |= QSerialPort::RingIndicatorSignal;
426 #elif defined(TIOCM_RI)
427 if (arg & TIOCM_RI)
428 ret |= QSerialPort::RingIndicatorSignal;
429 #endif
430 #ifdef TIOCM_DSR
431 if (arg & TIOCM_DSR)
432 ret |= QSerialPort::DataSetReadySignal;
433 #endif
434
435 return ret;
436 }
437
setDataTerminalReady(bool set)438 bool QSerialPortPrivate::setDataTerminalReady(bool set)
439 {
440 int status = TIOCM_DTR;
441 if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
442 setError(getSystemError());
443 return false;
444 }
445
446 return true;
447 }
448
setRequestToSend(bool set)449 bool QSerialPortPrivate::setRequestToSend(bool set)
450 {
451 int status = TIOCM_RTS;
452 if (::ioctl(descriptor, set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
453 setError(getSystemError());
454 return false;
455 }
456
457 return true;
458 }
459
flush()460 bool QSerialPortPrivate::flush()
461 {
462 return completeAsyncWrite();
463 }
464
clear(QSerialPort::Directions directions)465 bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
466 {
467 if (::tcflush(descriptor, (directions == QSerialPort::AllDirections)
468 ? TCIOFLUSH : (directions & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) == -1) {
469 setError(getSystemError());
470 return false;
471 }
472
473 return true;
474 }
475
sendBreak(int duration)476 bool QSerialPortPrivate::sendBreak(int duration)
477 {
478 if (::tcsendbreak(descriptor, duration) == -1) {
479 setError(getSystemError());
480 return false;
481 }
482
483 return true;
484 }
485
setBreakEnabled(bool set)486 bool QSerialPortPrivate::setBreakEnabled(bool set)
487 {
488 if (::ioctl(descriptor, set ? TIOCSBRK : TIOCCBRK) == -1) {
489 setError(getSystemError());
490 return false;
491 }
492
493 return true;
494 }
495
waitForReadyRead(int msecs)496 bool QSerialPortPrivate::waitForReadyRead(int msecs)
497 {
498 QElapsedTimer stopWatch;
499 stopWatch.start();
500
501 do {
502 bool readyToRead = false;
503 bool readyToWrite = false;
504 if (!waitForReadOrWrite(&readyToRead, &readyToWrite, true, !writeBuffer.isEmpty(),
505 qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
506 return false;
507 }
508
509 if (readyToRead)
510 return readNotification();
511
512 if (readyToWrite && !completeAsyncWrite())
513 return false;
514 } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
515 return false;
516 }
517
waitForBytesWritten(int msecs)518 bool QSerialPortPrivate::waitForBytesWritten(int msecs)
519 {
520 if (writeBuffer.isEmpty() && pendingBytesWritten <= 0)
521 return false;
522
523 QElapsedTimer stopWatch;
524 stopWatch.start();
525
526 for (;;) {
527 bool readyToRead = false;
528 bool readyToWrite = false;
529 const bool checkRead = q_func()->isReadable();
530 if (!waitForReadOrWrite(&readyToRead, &readyToWrite, checkRead, !writeBuffer.isEmpty(),
531 qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
532 return false;
533 }
534
535 if (readyToRead && !readNotification())
536 return false;
537
538 if (readyToWrite)
539 return completeAsyncWrite();
540 }
541 return false;
542 }
543
setBaudRate()544 bool QSerialPortPrivate::setBaudRate()
545 {
546 if (inputBaudRate == outputBaudRate)
547 return setBaudRate(inputBaudRate, QSerialPort::AllDirections);
548
549 return (setBaudRate(inputBaudRate, QSerialPort::Input)
550 && setBaudRate(outputBaudRate, QSerialPort::Output));
551 }
552
setStandardBaudRate(qint32 baudRate,QSerialPort::Directions directions)553 bool QSerialPortPrivate::setStandardBaudRate(qint32 baudRate, QSerialPort::Directions directions)
554 {
555 #ifdef Q_OS_LINUX
556 // try to clear custom baud rate, using termios v2
557 struct termios2 tio2;
558 if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
559 if (tio2.c_cflag & BOTHER) {
560 tio2.c_cflag &= ~BOTHER;
561 tio2.c_cflag |= CBAUD;
562 ::ioctl(descriptor, TCSETS2, &tio2);
563 }
564 }
565
566 // try to clear custom baud rate, using serial_struct (old way)
567 struct serial_struct serial;
568 ::memset(&serial, 0, sizeof(serial));
569 if (::ioctl(descriptor, TIOCGSERIAL, &serial) != -1) {
570 if (serial.flags & ASYNC_SPD_CUST) {
571 serial.flags &= ~ASYNC_SPD_CUST;
572 serial.custom_divisor = 0;
573 // we don't check on errors because a driver can has not this feature
574 ::ioctl(descriptor, TIOCSSERIAL, &serial);
575 }
576 }
577 #endif
578
579 termios tio;
580 if (!getTermios(&tio))
581 return false;
582
583 if ((directions & QSerialPort::Input) && ::cfsetispeed(&tio, baudRate) < 0) {
584 setError(getSystemError());
585 return false;
586 }
587
588 if ((directions & QSerialPort::Output) && ::cfsetospeed(&tio, baudRate) < 0) {
589 setError(getSystemError());
590 return false;
591 }
592
593 return setTermios(&tio);
594 }
595
596 #if defined(Q_OS_LINUX)
597
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)598 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
599 {
600 if (directions != QSerialPort::AllDirections) {
601 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
602 QSerialPort::tr("Cannot set custom speed for one direction")));
603 return false;
604 }
605
606 struct termios2 tio2;
607
608 if (::ioctl(descriptor, TCGETS2, &tio2) != -1) {
609 tio2.c_cflag &= ~CBAUD;
610 tio2.c_cflag |= BOTHER;
611
612 tio2.c_ispeed = baudRate;
613 tio2.c_ospeed = baudRate;
614
615 if (::ioctl(descriptor, TCSETS2, &tio2) != -1
616 && ::ioctl(descriptor, TCGETS2, &tio2) != -1) {
617 return true;
618 }
619 }
620
621 struct serial_struct serial;
622
623 if (::ioctl(descriptor, TIOCGSERIAL, &serial) == -1) {
624 setError(getSystemError());
625 return false;
626 }
627
628 serial.flags &= ~ASYNC_SPD_MASK;
629 serial.flags |= (ASYNC_SPD_CUST /* | ASYNC_LOW_LATENCY*/);
630 serial.custom_divisor = serial.baud_base / baudRate;
631
632 if (serial.custom_divisor == 0) {
633 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
634 QSerialPort::tr("No suitable custom baud rate divisor")));
635 return false;
636 }
637
638 if (serial.custom_divisor * baudRate != serial.baud_base) {
639 qWarning("Baud rate of serial port %s is set to %f instead of %d: divisor %f unsupported",
640 qPrintable(systemLocation),
641 float(serial.baud_base) / serial.custom_divisor,
642 baudRate, float(serial.baud_base) / baudRate);
643 }
644
645 if (::ioctl(descriptor, TIOCSSERIAL, &serial) == -1) {
646 setError(getSystemError());
647 return false;
648 }
649
650 return setStandardBaudRate(B38400, directions);
651 }
652
653 #elif defined(Q_OS_OSX)
654
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)655 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
656 {
657 if (directions != QSerialPort::AllDirections) {
658 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
659 QSerialPort::tr("Cannot set custom speed for one direction")));
660 return false;
661 }
662
663 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
664 if (::ioctl(descriptor, IOSSIOSPEED, &baudRate) == -1) {
665 setError(getSystemError());
666 return false;
667 }
668
669 return true;
670 #else
671 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
672 QSerialPort::tr("Custom baud rate is not supported")));
673 return false;
674 #endif
675 }
676
677 #elif defined(Q_OS_QNX)
678
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)679 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
680 {
681 // On QNX, the values of the 'Bxxxx' constants are set to 'xxxx' (i.e.
682 // B115200 is defined to '115200'), which means that literal values can be
683 // passed to cfsetispeed/cfsetospeed, including custom values, provided
684 // that the underlying hardware supports them.
685 return setStandardBaudRate(baudRate, directions);
686 }
687
688 #else
689
setCustomBaudRate(qint32 baudRate,QSerialPort::Directions directions)690 bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
691 {
692 Q_UNUSED(baudRate);
693 Q_UNUSED(directions);
694
695 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
696 QSerialPort::tr("Custom baud rate is not supported")));
697 return false;
698 }
699
700 #endif
701
setBaudRate(qint32 baudRate,QSerialPort::Directions directions)702 bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
703 {
704 if (baudRate <= 0) {
705 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Invalid baud rate value")));
706 return false;
707 }
708
709 const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate);
710
711 return (unixBaudRate > 0)
712 ? setStandardBaudRate(unixBaudRate, directions)
713 : setCustomBaudRate(baudRate, directions);
714 }
715
setDataBits(QSerialPort::DataBits dataBits)716 bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
717 {
718 termios tio;
719 if (!getTermios(&tio))
720 return false;
721
722 qt_set_databits(&tio, dataBits);
723
724 return setTermios(&tio);
725 }
726
setParity(QSerialPort::Parity parity)727 bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
728 {
729 termios tio;
730 if (!getTermios(&tio))
731 return false;
732
733 qt_set_parity(&tio, parity);
734
735 return setTermios(&tio);
736 }
737
setStopBits(QSerialPort::StopBits stopBits)738 bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
739 {
740 termios tio;
741 if (!getTermios(&tio))
742 return false;
743
744 qt_set_stopbits(&tio, stopBits);
745
746 return setTermios(&tio);
747 }
748
setFlowControl(QSerialPort::FlowControl flowControl)749 bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
750 {
751 termios tio;
752 if (!getTermios(&tio))
753 return false;
754
755 qt_set_flowcontrol(&tio, flowControl);
756
757 return setTermios(&tio);
758 }
759
startAsyncRead()760 bool QSerialPortPrivate::startAsyncRead()
761 {
762 setReadNotificationEnabled(true);
763 return true;
764 }
765
readNotification()766 bool QSerialPortPrivate::readNotification()
767 {
768 Q_Q(QSerialPort);
769
770 // Always buffered, read data from the port into the read buffer
771 qint64 newBytes = buffer.size();
772 qint64 bytesToRead = QSERIALPORT_BUFFERSIZE;
773
774 if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - buffer.size())) {
775 bytesToRead = readBufferMaxSize - buffer.size();
776 if (bytesToRead <= 0) {
777 // Buffer is full. User must read data from the buffer
778 // before we can read more from the port.
779 setReadNotificationEnabled(false);
780 return false;
781 }
782 }
783
784 char *ptr = buffer.reserve(bytesToRead);
785 const qint64 readBytes = readFromPort(ptr, bytesToRead);
786
787 buffer.chop(bytesToRead - qMax(readBytes, qint64(0)));
788
789 if (readBytes <= 0) {
790 QSerialPortErrorInfo error = getSystemError();
791 if (error.errorCode != QSerialPort::ResourceError)
792 error.errorCode = QSerialPort::ReadError;
793 else
794 setReadNotificationEnabled(false);
795 setError(error);
796 return false;
797 }
798
799 newBytes = buffer.size() - newBytes;
800
801 // only emit readyRead() when not recursing, and only if there is data available
802 const bool hasData = newBytes > 0;
803
804 if (!emittedReadyRead && hasData) {
805 emittedReadyRead = true;
806 emit q->readyRead();
807 emittedReadyRead = false;
808 }
809
810 return true;
811 }
812
startAsyncWrite()813 bool QSerialPortPrivate::startAsyncWrite()
814 {
815 if (writeBuffer.isEmpty() || writeSequenceStarted)
816 return true;
817
818 // Attempt to write it all in one chunk.
819 qint64 written = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize());
820 if (written < 0) {
821 QSerialPortErrorInfo error = getSystemError();
822 if (error.errorCode != QSerialPort::ResourceError)
823 error.errorCode = QSerialPort::WriteError;
824 setError(error);
825 return false;
826 }
827
828 writeBuffer.free(written);
829 pendingBytesWritten += written;
830 writeSequenceStarted = true;
831
832 if (!isWriteNotificationEnabled())
833 setWriteNotificationEnabled(true);
834 return true;
835 }
836
completeAsyncWrite()837 bool QSerialPortPrivate::completeAsyncWrite()
838 {
839 Q_Q(QSerialPort);
840
841 if (pendingBytesWritten > 0) {
842 if (!emittedBytesWritten) {
843 emittedBytesWritten = true;
844 emit q->bytesWritten(pendingBytesWritten);
845 pendingBytesWritten = 0;
846 emittedBytesWritten = false;
847 }
848 }
849
850 writeSequenceStarted = false;
851
852 if (writeBuffer.isEmpty()) {
853 setWriteNotificationEnabled(false);
854 return true;
855 }
856
857 return startAsyncWrite();
858 }
859
initialize(QIODevice::OpenMode mode)860 inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
861 {
862 #ifdef TIOCEXCL
863 if (::ioctl(descriptor, TIOCEXCL) == -1)
864 setError(getSystemError());
865 #endif
866
867 termios tio;
868 if (!getTermios(&tio))
869 return false;
870
871 restoredTermios = tio;
872
873 qt_set_common_props(&tio, mode);
874 qt_set_databits(&tio, dataBits);
875 qt_set_parity(&tio, parity);
876 qt_set_stopbits(&tio, stopBits);
877 qt_set_flowcontrol(&tio, flowControl);
878
879 if (!setTermios(&tio))
880 return false;
881
882 if (!setBaudRate())
883 return false;
884
885 if (mode & QIODevice::ReadOnly)
886 setReadNotificationEnabled(true);
887
888 return true;
889 }
890
writeData(const char * data,qint64 maxSize)891 qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
892 {
893 writeBuffer.append(data, maxSize);
894 if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
895 setWriteNotificationEnabled(true);
896 return maxSize;
897 }
898
setTermios(const termios * tio)899 bool QSerialPortPrivate::setTermios(const termios *tio)
900 {
901 if (::tcsetattr(descriptor, TCSANOW, tio) == -1) {
902 setError(getSystemError());
903 return false;
904 }
905 return true;
906 }
907
getTermios(termios * tio)908 bool QSerialPortPrivate::getTermios(termios *tio)
909 {
910 ::memset(tio, 0, sizeof(termios));
911 if (::tcgetattr(descriptor, tio) == -1) {
912 setError(getSystemError());
913 return false;
914 }
915 return true;
916 }
917
getSystemError(int systemErrorCode) const918 QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
919 {
920 if (systemErrorCode == -1)
921 systemErrorCode = errno;
922
923 QSerialPortErrorInfo error;
924 error.errorString = qt_error_string(systemErrorCode);
925
926 switch (systemErrorCode) {
927 case ENODEV:
928 error.errorCode = QSerialPort::DeviceNotFoundError;
929 break;
930 #ifdef ENOENT
931 case ENOENT:
932 error.errorCode = QSerialPort::DeviceNotFoundError;
933 break;
934 #endif
935 case EACCES:
936 error.errorCode = QSerialPort::PermissionError;
937 break;
938 case EBUSY:
939 error.errorCode = QSerialPort::PermissionError;
940 break;
941 case EAGAIN:
942 error.errorCode = QSerialPort::ResourceError;
943 break;
944 case EIO:
945 error.errorCode = QSerialPort::ResourceError;
946 break;
947 case EBADF:
948 error.errorCode = QSerialPort::ResourceError;
949 break;
950 #ifdef Q_OS_OSX
951 case ENXIO:
952 error.errorCode = QSerialPort::ResourceError;
953 break;
954 #endif
955 #ifdef EINVAL
956 case EINVAL:
957 error.errorCode = QSerialPort::UnsupportedOperationError;
958 break;
959 #endif
960 #ifdef ENOIOCTLCMD
961 case ENOIOCTLCMD:
962 error.errorCode = QSerialPort::UnsupportedOperationError;
963 break;
964 #endif
965 #ifdef ENOTTY
966 case ENOTTY:
967 error.errorCode = QSerialPort::UnsupportedOperationError;
968 break;
969 #endif
970 #ifdef EPERM
971 case EPERM:
972 error.errorCode = QSerialPort::PermissionError;
973 break;
974 #endif
975 default:
976 error.errorCode = QSerialPort::UnknownError;
977 break;
978 }
979 return error;
980 }
981
isReadNotificationEnabled() const982 bool QSerialPortPrivate::isReadNotificationEnabled() const
983 {
984 return readNotifier && readNotifier->isEnabled();
985 }
986
setReadNotificationEnabled(bool enable)987 void QSerialPortPrivate::setReadNotificationEnabled(bool enable)
988 {
989 Q_Q(QSerialPort);
990
991 if (readNotifier) {
992 readNotifier->setEnabled(enable);
993 } else if (enable) {
994 readNotifier = new ReadNotifier(this, q);
995 readNotifier->setEnabled(true);
996 }
997 }
998
isWriteNotificationEnabled() const999 bool QSerialPortPrivate::isWriteNotificationEnabled() const
1000 {
1001 return writeNotifier && writeNotifier->isEnabled();
1002 }
1003
setWriteNotificationEnabled(bool enable)1004 void QSerialPortPrivate::setWriteNotificationEnabled(bool enable)
1005 {
1006 Q_Q(QSerialPort);
1007
1008 if (writeNotifier) {
1009 writeNotifier->setEnabled(enable);
1010 } else if (enable) {
1011 writeNotifier = new WriteNotifier(this, q);
1012 writeNotifier->setEnabled(true);
1013 }
1014 }
1015
waitForReadOrWrite(bool * selectForRead,bool * selectForWrite,bool checkRead,bool checkWrite,int msecs)1016 bool QSerialPortPrivate::waitForReadOrWrite(bool *selectForRead, bool *selectForWrite,
1017 bool checkRead, bool checkWrite,
1018 int msecs)
1019 {
1020 Q_ASSERT(selectForRead);
1021 Q_ASSERT(selectForWrite);
1022
1023 pollfd pfd = qt_make_pollfd(descriptor, 0);
1024
1025 if (checkRead)
1026 pfd.events |= POLLIN;
1027
1028 if (checkWrite)
1029 pfd.events |= POLLOUT;
1030
1031 const int ret = qt_poll_msecs(&pfd, 1, msecs);
1032 if (ret < 0) {
1033 setError(getSystemError());
1034 return false;
1035 }
1036 if (ret == 0) {
1037 setError(QSerialPortErrorInfo(QSerialPort::TimeoutError));
1038 return false;
1039 }
1040 if (pfd.revents & POLLNVAL) {
1041 setError(getSystemError(EBADF));
1042 return false;
1043 }
1044
1045 *selectForWrite = ((pfd.revents & POLLOUT) != 0);
1046 *selectForRead = ((pfd.revents & POLLIN) != 0);
1047 return true;
1048 }
1049
readFromPort(char * data,qint64 maxSize)1050 qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
1051 {
1052 return qt_safe_read(descriptor, data, maxSize);
1053 }
1054
writeToPort(const char * data,qint64 maxSize)1055 qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
1056 {
1057 qint64 bytesWritten = 0;
1058 #if defined(CMSPAR)
1059 bytesWritten = qt_safe_write(descriptor, data, maxSize);
1060 #else
1061 if (parity != QSerialPort::MarkParity
1062 && parity != QSerialPort::SpaceParity) {
1063 bytesWritten = qt_safe_write(descriptor, data, maxSize);
1064 } else {// Perform parity emulation.
1065 bytesWritten = writePerChar(data, maxSize);
1066 }
1067 #endif
1068
1069 return bytesWritten;
1070 }
1071
1072 #ifndef CMSPAR
1073
evenParity(quint8 c)1074 static inline bool evenParity(quint8 c)
1075 {
1076 c ^= c >> 4; //(c7 ^ c3)(c6 ^ c2)(c5 ^ c1)(c4 ^ c0)
1077 c ^= c >> 2; //[(c7 ^ c3)(c5 ^ c1)][(c6 ^ c2)(c4 ^ c0)]
1078 c ^= c >> 1;
1079 return c & 1; //(c7 ^ c3)(c5 ^ c1)(c6 ^ c2)(c4 ^ c0)
1080 }
1081
writePerChar(const char * data,qint64 maxSize)1082 qint64 QSerialPortPrivate::writePerChar(const char *data, qint64 maxSize)
1083 {
1084 termios tio;
1085 if (!getTermios(&tio))
1086 return -1;
1087
1088 qint64 ret = 0;
1089 quint8 const charMask = (0xFF >> (8 - dataBits));
1090
1091 while (ret < maxSize) {
1092
1093 bool par = evenParity(*data & charMask);
1094 // False if need EVEN, true if need ODD.
1095 par ^= parity == QSerialPort::MarkParity;
1096 if (par ^ (tio.c_cflag & PARODD)) { // Need switch parity mode?
1097 tio.c_cflag ^= PARODD;
1098 flush(); //force sending already buffered data, because setTermios(&tio); cleares buffers
1099 //todo: add receiving buffered data!!!
1100 if (!setTermios(&tio))
1101 break;
1102 }
1103
1104 int r = qt_safe_write(descriptor, data, 1);
1105 if (r < 0)
1106 return -1;
1107 if (r > 0) {
1108 data += r;
1109 ret += r;
1110 }
1111 }
1112 return ret;
1113 }
1114
1115 #endif //CMSPAR
1116
1117 typedef QMap<qint32, qint32> BaudRateMap;
1118
1119 // The OS specific defines can be found in termios.h
1120
createStandardBaudRateMap()1121 static const BaudRateMap createStandardBaudRateMap()
1122 {
1123 BaudRateMap baudRateMap;
1124
1125 #ifdef B50
1126 baudRateMap.insert(50, B50);
1127 #endif
1128
1129 #ifdef B75
1130 baudRateMap.insert(75, B75);
1131 #endif
1132
1133 #ifdef B110
1134 baudRateMap.insert(110, B110);
1135 #endif
1136
1137 #ifdef B134
1138 baudRateMap.insert(134, B134);
1139 #endif
1140
1141 #ifdef B150
1142 baudRateMap.insert(150, B150);
1143 #endif
1144
1145 #ifdef B200
1146 baudRateMap.insert(200, B200);
1147 #endif
1148
1149 #ifdef B300
1150 baudRateMap.insert(300, B300);
1151 #endif
1152
1153 #ifdef B600
1154 baudRateMap.insert(600, B600);
1155 #endif
1156
1157 #ifdef B1200
1158 baudRateMap.insert(1200, B1200);
1159 #endif
1160
1161 #ifdef B1800
1162 baudRateMap.insert(1800, B1800);
1163 #endif
1164
1165 #ifdef B2400
1166 baudRateMap.insert(2400, B2400);
1167 #endif
1168
1169 #ifdef B4800
1170 baudRateMap.insert(4800, B4800);
1171 #endif
1172
1173 #ifdef B7200
1174 baudRateMap.insert(7200, B7200);
1175 #endif
1176
1177 #ifdef B9600
1178 baudRateMap.insert(9600, B9600);
1179 #endif
1180
1181 #ifdef B14400
1182 baudRateMap.insert(14400, B14400);
1183 #endif
1184
1185 #ifdef B19200
1186 baudRateMap.insert(19200, B19200);
1187 #endif
1188
1189 #ifdef B28800
1190 baudRateMap.insert(28800, B28800);
1191 #endif
1192
1193 #ifdef B38400
1194 baudRateMap.insert(38400, B38400);
1195 #endif
1196
1197 #ifdef B57600
1198 baudRateMap.insert(57600, B57600);
1199 #endif
1200
1201 #ifdef B76800
1202 baudRateMap.insert(76800, B76800);
1203 #endif
1204
1205 #ifdef B115200
1206 baudRateMap.insert(115200, B115200);
1207 #endif
1208
1209 #ifdef B230400
1210 baudRateMap.insert(230400, B230400);
1211 #endif
1212
1213 #ifdef B460800
1214 baudRateMap.insert(460800, B460800);
1215 #endif
1216
1217 #ifdef B500000
1218 baudRateMap.insert(500000, B500000);
1219 #endif
1220
1221 #ifdef B576000
1222 baudRateMap.insert(576000, B576000);
1223 #endif
1224
1225 #ifdef B921600
1226 baudRateMap.insert(921600, B921600);
1227 #endif
1228
1229 #ifdef B1000000
1230 baudRateMap.insert(1000000, B1000000);
1231 #endif
1232
1233 #ifdef B1152000
1234 baudRateMap.insert(1152000, B1152000);
1235 #endif
1236
1237 #ifdef B1500000
1238 baudRateMap.insert(1500000, B1500000);
1239 #endif
1240
1241 #ifdef B2000000
1242 baudRateMap.insert(2000000, B2000000);
1243 #endif
1244
1245 #ifdef B2500000
1246 baudRateMap.insert(2500000, B2500000);
1247 #endif
1248
1249 #ifdef B3000000
1250 baudRateMap.insert(3000000, B3000000);
1251 #endif
1252
1253 #ifdef B3500000
1254 baudRateMap.insert(3500000, B3500000);
1255 #endif
1256
1257 #ifdef B4000000
1258 baudRateMap.insert(4000000, B4000000);
1259 #endif
1260
1261 return baudRateMap;
1262 }
1263
standardBaudRateMap()1264 static const BaudRateMap& standardBaudRateMap()
1265 {
1266 static const BaudRateMap baudRateMap = createStandardBaudRateMap();
1267 return baudRateMap;
1268 }
1269
settingFromBaudRate(qint32 baudRate)1270 qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
1271 {
1272 return standardBaudRateMap().value(baudRate);
1273 }
1274
standardBaudRates()1275 QList<qint32> QSerialPortPrivate::standardBaudRates()
1276 {
1277 return standardBaudRateMap().keys();
1278 }
1279
handle() const1280 QSerialPort::Handle QSerialPort::handle() const
1281 {
1282 Q_D(const QSerialPort);
1283 return d->descriptor;
1284 }
1285
1286 QT_END_NAMESPACE
1287