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)
77struct 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
103QT_BEGIN_NAMESPACE
104
105QString 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(type: QStandardPaths::TempLocation);
120
121 QString fileName = portName;
122 fileName.replace(before: QLatin1Char('/'), after: QLatin1Char('_'));
123 fileName.prepend(s: 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(fileName: filePath) || lockDirectoryInfo.isWritable()) {
133 lockFilePath = filePath;
134 break;
135 }
136 }
137 }
138
139 if (lockFilePath.isEmpty()) {
140 qWarning(msg: "The following directories are not readable or writable for detaling with lock files\n");
141 for (const QString &lockDirectoryPath : lockDirectoryPaths)
142 qWarning(msg: "\t%s\n", qPrintable(lockDirectoryPath));
143 return QString();
144 }
145
146 return lockFilePath;
147}
148
149class ReadNotifier : public QSocketNotifier
150{
151public:
152 explicit ReadNotifier(QSerialPortPrivate *d, QObject *parent)
153 : QSocketNotifier(d->descriptor, QSocketNotifier::Read, parent)
154 , dptr(d)
155 {
156 }
157
158protected:
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
168private:
169 QSerialPortPrivate * const dptr;
170};
171
172class WriteNotifier : public QSocketNotifier
173{
174public:
175 explicit WriteNotifier(QSerialPortPrivate *d, QObject *parent)
176 : QSocketNotifier(d->descriptor, QSocketNotifier::Write, parent)
177 , dptr(d)
178 {
179 }
180
181protected:
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
191private:
192 QSerialPortPrivate * const dptr;
193};
194
195static 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(termios_p: 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
215static 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
237static 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
272static 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
287static 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
309bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
310{
311 QString lockFilePath = serialPortLockFilePath(portName: QSerialPortInfoPrivate::portNameFromSystemLocation(source: systemLocation));
312 bool isLockFileEmpty = lockFilePath.isEmpty();
313 if (isLockFileEmpty) {
314 qWarning(msg: "Failed to create a lock file for opening the device");
315 setError(QSerialPortErrorInfo(QSerialPort::PermissionError, QSerialPort::tr(s: "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(s: "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(pathname: 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(fd: descriptor);
349 return false;
350 }
351
352 lockFileScopedPointer.swap(other&: newLockFileScopedPointer);
353
354 return true;
355}
356
357void QSerialPortPrivate::close()
358{
359 if (settingsRestoredOnClose)
360 ::tcsetattr(fd: descriptor, TCSANOW, termios_p: &restoredTermios);
361
362#ifdef TIOCNXCL
363 ::ioctl(fd: descriptor, TIOCNXCL);
364#endif
365
366 delete readNotifier;
367 readNotifier = nullptr;
368
369 delete writeNotifier;
370 writeNotifier = nullptr;
371
372 qt_safe_close(fd: descriptor);
373
374 lockFileScopedPointer.reset(other: nullptr);
375
376 descriptor = -1;
377 pendingBytesWritten = 0;
378 writeSequenceStarted = false;
379}
380
381QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
382{
383 int arg = 0;
384
385 if (::ioctl(fd: 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
438bool QSerialPortPrivate::setDataTerminalReady(bool set)
439{
440 int status = TIOCM_DTR;
441 if (::ioctl(fd: descriptor, request: set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
442 setError(getSystemError());
443 return false;
444 }
445
446 return true;
447}
448
449bool QSerialPortPrivate::setRequestToSend(bool set)
450{
451 int status = TIOCM_RTS;
452 if (::ioctl(fd: descriptor, request: set ? TIOCMBIS : TIOCMBIC, &status) == -1) {
453 setError(getSystemError());
454 return false;
455 }
456
457 return true;
458}
459
460bool QSerialPortPrivate::flush()
461{
462 return completeAsyncWrite();
463}
464
465bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
466{
467 if (::tcflush(fd: descriptor, queue_selector: (directions == QSerialPort::AllDirections)
468 ? TCIOFLUSH : (directions & QSerialPort::Input) ? TCIFLUSH : TCOFLUSH) == -1) {
469 setError(getSystemError());
470 return false;
471 }
472
473 return true;
474}
475
476bool QSerialPortPrivate::sendBreak(int duration)
477{
478 if (::tcsendbreak(fd: descriptor, duration: duration) == -1) {
479 setError(getSystemError());
480 return false;
481 }
482
483 return true;
484}
485
486bool QSerialPortPrivate::setBreakEnabled(bool set)
487{
488 if (::ioctl(fd: descriptor, request: set ? TIOCSBRK : TIOCCBRK) == -1) {
489 setError(getSystemError());
490 return false;
491 }
492
493 return true;
494}
495
496bool 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(selectForRead: &readyToRead, selectForWrite: &readyToWrite, checkRead: true, checkWrite: !writeBuffer.isEmpty(),
505 msecs: qt_subtract_from_timeout(timeout: msecs, elapsed: 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(timeout: msecs, elapsed: stopWatch.elapsed()) > 0);
515 return false;
516}
517
518bool 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(selectForRead: &readyToRead, selectForWrite: &readyToWrite, checkRead, checkWrite: !writeBuffer.isEmpty(),
531 msecs: qt_subtract_from_timeout(timeout: msecs, elapsed: 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
544bool QSerialPortPrivate::setBaudRate()
545{
546 if (inputBaudRate == outputBaudRate)
547 return setBaudRate(baudRate: inputBaudRate, directions: QSerialPort::AllDirections);
548
549 return (setBaudRate(baudRate: inputBaudRate, directions: QSerialPort::Input)
550 && setBaudRate(baudRate: outputBaudRate, directions: QSerialPort::Output));
551}
552
553bool 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(fd: descriptor, TCGETS2, &tio2) != -1) {
559 if (tio2.c_cflag & BOTHER) {
560 tio2.c_cflag &= ~BOTHER;
561 tio2.c_cflag |= CBAUD;
562 ::ioctl(fd: 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(s: &serial, c: 0, n: sizeof(serial));
569 if (::ioctl(fd: 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(fd: descriptor, TIOCSSERIAL, &serial);
575 }
576 }
577#endif
578
579 termios tio;
580 if (!getTermios(tio: &tio))
581 return false;
582
583 if ((directions & QSerialPort::Input) && ::cfsetispeed(termios_p: &tio, speed: baudRate) < 0) {
584 setError(getSystemError());
585 return false;
586 }
587
588 if ((directions & QSerialPort::Output) && ::cfsetospeed(termios_p: &tio, speed: baudRate) < 0) {
589 setError(getSystemError());
590 return false;
591 }
592
593 return setTermios(&tio);
594}
595
596#if defined(Q_OS_LINUX)
597
598bool QSerialPortPrivate::setCustomBaudRate(qint32 baudRate, QSerialPort::Directions directions)
599{
600 if (directions != QSerialPort::AllDirections) {
601 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError,
602 QSerialPort::tr(s: "Cannot set custom speed for one direction")));
603 return false;
604 }
605
606 struct termios2 tio2;
607
608 if (::ioctl(fd: 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(fd: descriptor, TCSETS2, &tio2) != -1
616 && ::ioctl(fd: descriptor, TCGETS2, &tio2) != -1) {
617 return true;
618 }
619 }
620
621 struct serial_struct serial;
622
623 if (::ioctl(fd: 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(s: "No suitable custom baud rate divisor")));
635 return false;
636 }
637
638 if (serial.custom_divisor * baudRate != serial.baud_base) {
639 qWarning(msg: "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(fd: 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
655bool 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
679bool 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
690bool 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
702bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
703{
704 if (baudRate <= 0) {
705 setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr(s: "Invalid baud rate value")));
706 return false;
707 }
708
709 const qint32 unixBaudRate = QSerialPortPrivate::settingFromBaudRate(baudRate);
710
711 return (unixBaudRate > 0)
712 ? setStandardBaudRate(baudRate: unixBaudRate, directions)
713 : setCustomBaudRate(baudRate, directions);
714}
715
716bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
717{
718 termios tio;
719 if (!getTermios(tio: &tio))
720 return false;
721
722 qt_set_databits(tio: &tio, databits: dataBits);
723
724 return setTermios(&tio);
725}
726
727bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
728{
729 termios tio;
730 if (!getTermios(tio: &tio))
731 return false;
732
733 qt_set_parity(tio: &tio, parity);
734
735 return setTermios(&tio);
736}
737
738bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
739{
740 termios tio;
741 if (!getTermios(tio: &tio))
742 return false;
743
744 qt_set_stopbits(tio: &tio, stopbits: stopBits);
745
746 return setTermios(&tio);
747}
748
749bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
750{
751 termios tio;
752 if (!getTermios(tio: &tio))
753 return false;
754
755 qt_set_flowcontrol(tio: &tio, flowcontrol: flowControl);
756
757 return setTermios(&tio);
758}
759
760bool QSerialPortPrivate::startAsyncRead()
761{
762 setReadNotificationEnabled(true);
763 return true;
764}
765
766bool 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(bytes: bytesToRead);
785 const qint64 readBytes = readFromPort(data: ptr, maxSize: bytesToRead);
786
787 buffer.chop(bytes: bytesToRead - qMax(a: readBytes, b: 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
813bool 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(data: writeBuffer.readPointer(), maxSize: 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(bytes: written);
829 pendingBytesWritten += written;
830 writeSequenceStarted = true;
831
832 if (!isWriteNotificationEnabled())
833 setWriteNotificationEnabled(true);
834 return true;
835}
836
837bool QSerialPortPrivate::completeAsyncWrite()
838{
839 Q_Q(QSerialPort);
840
841 if (pendingBytesWritten > 0) {
842 if (!emittedBytesWritten) {
843 emittedBytesWritten = true;
844 emit q->bytesWritten(bytes: 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
860inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
861{
862#ifdef TIOCEXCL
863 if (::ioctl(fd: descriptor, TIOCEXCL) == -1)
864 setError(getSystemError());
865#endif
866
867 termios tio;
868 if (!getTermios(tio: &tio))
869 return false;
870
871 restoredTermios = tio;
872
873 qt_set_common_props(tio: &tio, m: mode);
874 qt_set_databits(tio: &tio, databits: dataBits);
875 qt_set_parity(tio: &tio, parity);
876 qt_set_stopbits(tio: &tio, stopbits: stopBits);
877 qt_set_flowcontrol(tio: &tio, flowcontrol: 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
891qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
892{
893 writeBuffer.append(data, size: maxSize);
894 if (!writeBuffer.isEmpty() && !isWriteNotificationEnabled())
895 setWriteNotificationEnabled(true);
896 return maxSize;
897}
898
899bool QSerialPortPrivate::setTermios(const termios *tio)
900{
901 if (::tcsetattr(fd: descriptor, TCSANOW, termios_p: tio) == -1) {
902 setError(getSystemError());
903 return false;
904 }
905 return true;
906}
907
908bool QSerialPortPrivate::getTermios(termios *tio)
909{
910 ::memset(s: tio, c: 0, n: sizeof(termios));
911 if (::tcgetattr(fd: descriptor, termios_p: tio) == -1) {
912 setError(getSystemError());
913 return false;
914 }
915 return true;
916}
917
918QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
919{
920 if (systemErrorCode == -1)
921 systemErrorCode = errno;
922
923 QSerialPortErrorInfo error;
924 error.errorString = qt_error_string(errorCode: 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
982bool QSerialPortPrivate::isReadNotificationEnabled() const
983{
984 return readNotifier && readNotifier->isEnabled();
985}
986
987void 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
999bool QSerialPortPrivate::isWriteNotificationEnabled() const
1000{
1001 return writeNotifier && writeNotifier->isEnabled();
1002}
1003
1004void 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
1016bool 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(fd: descriptor, events: 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(fds: &pfd, nfds: 1, timeout: 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
1050qint64 QSerialPortPrivate::readFromPort(char *data, qint64 maxSize)
1051{
1052 return qt_safe_read(fd: descriptor, data, maxlen: maxSize);
1053}
1054
1055qint64 QSerialPortPrivate::writeToPort(const char *data, qint64 maxSize)
1056{
1057 qint64 bytesWritten = 0;
1058#if defined(CMSPAR)
1059 bytesWritten = qt_safe_write(fd: descriptor, data, len: 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
1074static 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
1082qint64 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
1117typedef QMap<qint32, qint32> BaudRateMap;
1118
1119// The OS specific defines can be found in termios.h
1120
1121static const BaudRateMap createStandardBaudRateMap()
1122{
1123 BaudRateMap baudRateMap;
1124
1125#ifdef B50
1126 baudRateMap.insert(akey: 50, B50);
1127#endif
1128
1129#ifdef B75
1130 baudRateMap.insert(akey: 75, B75);
1131#endif
1132
1133#ifdef B110
1134 baudRateMap.insert(akey: 110, B110);
1135#endif
1136
1137#ifdef B134
1138 baudRateMap.insert(akey: 134, B134);
1139#endif
1140
1141#ifdef B150
1142 baudRateMap.insert(akey: 150, B150);
1143#endif
1144
1145#ifdef B200
1146 baudRateMap.insert(akey: 200, B200);
1147#endif
1148
1149#ifdef B300
1150 baudRateMap.insert(akey: 300, B300);
1151#endif
1152
1153#ifdef B600
1154 baudRateMap.insert(akey: 600, B600);
1155#endif
1156
1157#ifdef B1200
1158 baudRateMap.insert(akey: 1200, B1200);
1159#endif
1160
1161#ifdef B1800
1162 baudRateMap.insert(akey: 1800, B1800);
1163#endif
1164
1165#ifdef B2400
1166 baudRateMap.insert(akey: 2400, B2400);
1167#endif
1168
1169#ifdef B4800
1170 baudRateMap.insert(akey: 4800, B4800);
1171#endif
1172
1173#ifdef B7200
1174 baudRateMap.insert(7200, B7200);
1175#endif
1176
1177#ifdef B9600
1178 baudRateMap.insert(akey: 9600, B9600);
1179#endif
1180
1181#ifdef B14400
1182 baudRateMap.insert(14400, B14400);
1183#endif
1184
1185#ifdef B19200
1186 baudRateMap.insert(akey: 19200, B19200);
1187#endif
1188
1189#ifdef B28800
1190 baudRateMap.insert(28800, B28800);
1191#endif
1192
1193#ifdef B38400
1194 baudRateMap.insert(akey: 38400, B38400);
1195#endif
1196
1197#ifdef B57600
1198 baudRateMap.insert(akey: 57600, B57600);
1199#endif
1200
1201#ifdef B76800
1202 baudRateMap.insert(76800, B76800);
1203#endif
1204
1205#ifdef B115200
1206 baudRateMap.insert(akey: 115200, B115200);
1207#endif
1208
1209#ifdef B230400
1210 baudRateMap.insert(akey: 230400, B230400);
1211#endif
1212
1213#ifdef B460800
1214 baudRateMap.insert(akey: 460800, B460800);
1215#endif
1216
1217#ifdef B500000
1218 baudRateMap.insert(akey: 500000, B500000);
1219#endif
1220
1221#ifdef B576000
1222 baudRateMap.insert(akey: 576000, B576000);
1223#endif
1224
1225#ifdef B921600
1226 baudRateMap.insert(akey: 921600, B921600);
1227#endif
1228
1229#ifdef B1000000
1230 baudRateMap.insert(akey: 1000000, B1000000);
1231#endif
1232
1233#ifdef B1152000
1234 baudRateMap.insert(akey: 1152000, B1152000);
1235#endif
1236
1237#ifdef B1500000
1238 baudRateMap.insert(akey: 1500000, B1500000);
1239#endif
1240
1241#ifdef B2000000
1242 baudRateMap.insert(akey: 2000000, B2000000);
1243#endif
1244
1245#ifdef B2500000
1246 baudRateMap.insert(akey: 2500000, B2500000);
1247#endif
1248
1249#ifdef B3000000
1250 baudRateMap.insert(akey: 3000000, B3000000);
1251#endif
1252
1253#ifdef B3500000
1254 baudRateMap.insert(akey: 3500000, B3500000);
1255#endif
1256
1257#ifdef B4000000
1258 baudRateMap.insert(akey: 4000000, B4000000);
1259#endif
1260
1261 return baudRateMap;
1262}
1263
1264static const BaudRateMap& standardBaudRateMap()
1265{
1266 static const BaudRateMap baudRateMap = createStandardBaudRateMap();
1267 return baudRateMap;
1268}
1269
1270qint32 QSerialPortPrivate::settingFromBaudRate(qint32 baudRate)
1271{
1272 return standardBaudRateMap().value(akey: baudRate);
1273}
1274
1275QList<qint32> QSerialPortPrivate::standardBaudRates()
1276{
1277 return standardBaudRateMap().keys();
1278}
1279
1280QSerialPort::Handle QSerialPort::handle() const
1281{
1282 Q_D(const QSerialPort);
1283 return d->descriptor;
1284}
1285
1286QT_END_NAMESPACE
1287

source code of qtserialport/src/serialport/qserialport_unix.cpp