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

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