QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
qserialport_android.cpp
Go to the documentation of this file.
1#include <algorithm>
2#include <iterator>
3#include <limits>
4#include <utility>
5
6#include <QtCore/QMetaObject>
7#include <QtCore/QPointer>
8#include <QtCore/QScopeGuard>
9
10#include "QGCLoggingCategory.h"
11#include "qserialport_p.h"
12
13QGC_LOGGING_CATEGORY(AndroidSerialPortLog, "Android.AndroidSerialPort")
14
16
17bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
18{
20 return _posixOpen(mode);
21 }
22
23 qCDebug(AndroidSerialPortLog) << "Opening" << systemLocation;
24
26 auto tokenGuard = qScopeGuard([this]() { AndroidSerial::unregisterPointer(this); });
27
28 _deviceId = AndroidSerial::open(systemLocation, this);
29 if (_deviceId == INVALID_DEVICE_ID) {
30 qCWarning(AndroidSerialPortLog) << "Error opening" << systemLocation;
32 return false;
33 }
34
35 descriptor = AndroidSerial::getDeviceHandle(_deviceId);
36 if (descriptor == -1) {
37 qCWarning(AndroidSerialPortLog) << "Failed to get device handle for" << systemLocation;
39 close();
40 return false;
41 }
42
43 if (!_setParameters(inputBaudRate, dataBits, stopBits, parity)) {
44 qCWarning(AndroidSerialPortLog) << "Failed to set serial port parameters for" << systemLocation;
45 close();
46 return false;
47 }
48
49 if (!setFlowControl(flowControl)) {
50 qCWarning(AndroidSerialPortLog) << "Failed to set serial port flow control for" << systemLocation;
51 close();
52 return false;
53 }
54
55 if (mode & QIODevice::ReadOnly) {
56 if (!startAsyncRead()) {
57 qCWarning(AndroidSerialPortLog) << "Failed to start async read for" << systemLocation;
58 close();
59 return false;
60 }
61 } else if (mode & QIODevice::WriteOnly) {
62 if (!_stopAsyncRead()) {
63 qCWarning(AndroidSerialPortLog) << "Failed to stop async read for" << systemLocation;
64 }
65 }
66
67 (void)clear(QSerialPort::AllDirections);
68 tokenGuard.dismiss();
69
70 return true;
71}
72
74{
76 _posixClose();
77 return;
78 }
79
80 qCDebug(AndroidSerialPortLog) << "Closing" << systemLocation;
81
82 _stopAsyncRead();
83
84 {
85 // Drop any undelivered data so a queued drain or later re-open can't
86 // deliver stale bytes into cleared QIODevice buffers.
87 QMutexLocker locker(&_readMutex);
88 _pendingData.clear();
89 _pendingDataOffset = 0;
90 _readyReadPending.store(false);
91 _bufferBytesEstimate.store(0, std::memory_order_relaxed);
92 }
93
94 if (_deviceId != INVALID_DEVICE_ID) {
95 if (!AndroidSerial::close(_deviceId)) {
96 qCWarning(AndroidSerialPortLog) << "Failed to close device with ID" << _deviceId;
97 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Closing device failed")));
98 }
99 _deviceId = INVALID_DEVICE_ID;
100 }
101
102 descriptor = -1;
103
105}
106
108{
109 qCWarning(AndroidSerialPortLog) << "Exception arrived on device ID" << _deviceId << ":" << ex;
111}
112
114{
116 return _posixStartAsyncRead();
117 }
118
119 if (!AndroidSerial::readThreadRunning(_deviceId)) {
120 const bool result = AndroidSerial::startReadThread(_deviceId);
121 if (!result) {
122 qCWarning(AndroidSerialPortLog) << "Failed to start async read thread for device ID" << _deviceId;
123 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to start async read")));
124 return false;
125 }
126 }
127
128 // If pending bytes were left behind due to read buffer backpressure,
129 // schedule another drain as soon as reads are active again.
130 _scheduleReadyRead();
131
132 return true;
133}
134
135bool QSerialPortPrivate::_stopAsyncRead()
136{
138 return _posixStopAsyncRead();
139 }
140
141 bool result = true;
142
143 if (AndroidSerial::readThreadRunning(_deviceId)) {
144 result = AndroidSerial::stopReadThread(_deviceId);
145 if (!result) {
146 qCWarning(AndroidSerialPortLog) << "Failed to stop async read thread for device ID" << _deviceId;
147 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to stop async read")));
148 }
149 }
150
151 return result;
152}
153
154qint64 QSerialPortPrivate::_drainPendingDataLocked(qint64 maxBytes)
155{
156 const qsizetype pendingSize = _pendingSizeLocked();
157 if (pendingSize <= 0) {
158 _pendingData.clear();
159 _pendingDataOffset = 0;
160 return 0;
161 }
162
163 qint64 toDrain = pendingSize;
164 if (maxBytes >= 0) {
165 toDrain = qMin(toDrain, maxBytes);
166 }
167
168 if (toDrain <= 0) {
169 return 0;
170 }
171
172 buffer.append(_pendingData.constData() + _pendingDataOffset, toDrain);
173 _pendingDataOffset += static_cast<qsizetype>(toDrain);
174
175 if (_pendingDataOffset >= _pendingData.size()) {
176 _pendingData.clear();
177 _pendingDataOffset = 0;
178 } else {
179 // Compact occasionally to keep append operations efficient without
180 // paying the cost on every drain.
181 constexpr qsizetype kCompactThreshold = 4096;
182 if (_pendingDataOffset >= kCompactThreshold && (_pendingDataOffset * 2) >= _pendingData.size()) {
183 _compactPendingDataLocked();
184 }
185 }
186
187 _bufferBytesEstimate.store(buffer.size(), std::memory_order_relaxed);
188 return toDrain;
189}
190
191qsizetype QSerialPortPrivate::_pendingSizeLocked() const
192{
193 return qMax<qsizetype>(0, _pendingData.size() - _pendingDataOffset);
194}
195
196void QSerialPortPrivate::_compactPendingDataLocked()
197{
198 if (_pendingDataOffset <= 0) {
199 return;
200 }
201
202 if (_pendingDataOffset >= _pendingData.size()) {
203 _pendingData.clear();
204 _pendingDataOffset = 0;
205 return;
206 }
207
208 _pendingData.remove(0, _pendingDataOffset);
209 _pendingDataOffset = 0;
210}
211
212void QSerialPortPrivate::newDataArrived(const char* bytes, int length)
213{
214 // qCDebug(AndroidSerialPortLog) << "newDataArrived" << length;
215
216 qint64 droppedBytes = 0;
217
218 QMutexLocker locker(&_readMutex);
219 int bytesToRead = length;
220 if (readBufferMaxSize) {
221 const qint64 totalBuffered = _pendingSizeLocked() + _bufferBytesEstimate.load(std::memory_order_relaxed);
222 const qint64 headroom = readBufferMaxSize - totalBuffered;
223 if (bytesToRead > headroom) {
224 bytesToRead = static_cast<int>(qMax(qint64(0), headroom));
225 droppedBytes = static_cast<qint64>(length - bytesToRead);
226 }
227 }
228
229 if (bytesToRead > 0) {
230 constexpr qsizetype kCompactBeforeAppendThreshold = 8192;
231 if (_pendingDataOffset >= kCompactBeforeAppendThreshold) {
232 _compactPendingDataLocked();
233 }
234 _pendingData.append(bytes, bytesToRead);
235 _readWaitCondition.wakeAll();
236 }
237 locker.unlock();
238
239 if (droppedBytes > 0) {
240 qCWarning(AndroidSerialPortLog) << "Read buffer full, dropping" << droppedBytes << "bytes";
241 }
242
243 if (bytesToRead <= 0) {
244 return;
245 }
246
247 _scheduleReadyRead();
248}
249
250void QSerialPortPrivate::_scheduleReadyRead()
251{
252 Q_Q(QSerialPort);
253
254 if (!_readyReadPending.exchange(true)) {
255 QPointer<QSerialPort> guard(q);
256 QMetaObject::invokeMethod(
257 q,
258 [this, guard]() {
259 if (!guard || !guard->isOpen()) {
260 // Device closed before the queued drain ran. close() clears the
261 // QIODevice read buffers, so draining into them would assert.
262 _readyReadPending.store(false);
263 return;
264 }
265
266 QMutexLocker locker(&_readMutex);
267 if (_pendingSizeLocked() <= 0) {
268 _readyReadPending.store(false);
269 return;
270 }
271
272 if (readBufferMaxSize > 0) {
273 const qint64 canAccept = readBufferMaxSize - buffer.size();
274 if (canAccept > 0) {
275 (void)_drainPendingDataLocked(canAccept);
276 }
277 } else {
278 (void)_drainPendingDataLocked();
279 }
280
281 // Reset flag after drain so data arriving during the drain
282 // does not enqueue redundant lambdas. If pending data remains,
283 // reschedule so nothing is left undelivered.
284 const bool more = (_pendingSizeLocked() > 0);
285 _readyReadPending.store(false);
286
287 _readWaitCondition.wakeAll();
288 locker.unlock();
289
290 emit guard->readyRead();
291
292 if (more) {
293 _scheduleReadyRead();
294 }
295 },
296 Qt::QueuedConnection);
297 }
298}
299
300bool QSerialPortPrivate::waitForReadyRead(int msecs)
301{
302 // One deadline covers both steps, so the wait never exceeds msecs.
303 const QDeadlineTimer deadline(msecs);
304 // Desktop QSerialPort also sends pending writes while waiting for input.
305 (void) _writeDataOneShot(msecs);
306
308 return _posixWaitForReadyRead(static_cast<int>(deadline.remainingTime()));
309 }
310
311 QMutexLocker locker(&_readMutex);
312 if (!buffer.isEmpty()) {
313 return true;
314 }
315
316 if (_pendingSizeLocked() > 0) {
317 (void)_drainPendingDataLocked();
318 return true;
319 }
320
321 while (buffer.isEmpty() && (_pendingSizeLocked() <= 0)) {
322 if (!_readWaitCondition.wait(&_readMutex, deadline)) {
323 break;
324 }
325
326 if (!buffer.isEmpty()) {
327 return true;
328 }
329
330 if (_pendingSizeLocked() > 0) {
331 (void)_drainPendingDataLocked();
332 return true;
333 }
334 }
335 locker.unlock();
336
337 qCDebug(AndroidSerialPortLog) << "Timeout while waiting for ready read on device ID" << _deviceId;
338 setError(QSerialPortErrorInfo(QSerialPort::TimeoutError, QSerialPort::tr("Timeout while waiting for ready read")));
339
340 return false;
341}
342
344{
345 if (writeBuffer.isEmpty()) {
346 return false;
347 }
348
349 return _writeDataOneShot(msecs);
350}
351
352int QSerialPortPrivate::_writeTimeoutMs(const QDeadlineTimer& deadline)
353{
354 // The USB backend treats zero as unbounded, so an expired deadline still gets a minimal attempt.
355 if (deadline.isForever()) {
356 return 0;
357 }
358 return static_cast<int>(std::clamp<qint64>(deadline.remainingTime(), 1, std::numeric_limits<int>::max()));
359}
360
361bool QSerialPortPrivate::_writeDataOneShot(int msecs)
362{
363 Q_Q(QSerialPort);
364
365 if (writeBuffer.isEmpty()) {
366 return true;
367 }
368
369 const QDeadlineTimer deadline(msecs);
370 qint64 written = 0;
371 bool complete = true;
372 while (!writeBuffer.isEmpty()) {
373 const qint64 blockSize = writeBuffer.nextDataBlockSize();
374 const qint64 result = _writeToPortWithProgress(writeBuffer.readPointer(), blockSize, _writeTimeoutMs(deadline));
375 if (result < 0) {
376 complete = false;
377 break;
378 }
379
380 writeBuffer.free(result);
381 written += result;
382 if (result < blockSize) {
383 qCDebug(AndroidSerialPortLog)
384 << "Write timed out on device ID" << _deviceId << "after" << written << "bytes";
385 setError(QSerialPortErrorInfo(QSerialPort::TimeoutError, QSerialPort::tr("Timeout while writing data")));
386 complete = false;
387 break;
388 }
389 }
390
391 if (written > 0) {
392 emit q->bytesWritten(written);
393 }
394
395 return complete;
396}
397
398void QSerialPortPrivate::_scheduleWrite()
399{
400 Q_Q(QSerialPort);
401
402 if (std::exchange(_writePending, true)) {
403 return;
404 }
405
406 QPointer<QSerialPort> guard(q);
407 QMetaObject::invokeMethod(
408 q,
409 [this, guard]() {
410 if (!guard) {
411 return;
412 }
413 _writePending = false;
414 if (!guard->isOpen() || writeBuffer.isEmpty()) {
415 return;
416 }
417
418 const qint64 pending = writeBuffer.size();
419 (void) _writeDataOneShot();
420 // Keep draining while the backend makes progress; errors wait for the next write or wait call.
421 if (guard && guard->isOpen() && !writeBuffer.isEmpty() && writeBuffer.size() < pending) {
422 _scheduleWrite();
423 }
424 },
425 Qt::QueuedConnection);
426}
427
428qint64 QSerialPortPrivate::_writeToPort(const char* data, qint64 maxSize, int timeout, bool async)
429{
430 if (async && AndroidSerial::usePosixSerial()) {
431 qCWarning(AndroidSerialPortLog) << "Async write is not supported by the POSIX backend; writing synchronously";
432 }
433
434 const qint64 result = AndroidSerial::usePosixSerial()
435 ? _posixWrite(data, maxSize, timeout)
436 : AndroidSerial::write(_deviceId, data, maxSize, timeout, async);
437 if (result < 0) {
438 qCWarning(AndroidSerialPortLog) << "Failed to write to port" << systemLocation;
439 setError(QSerialPortErrorInfo(QSerialPort::WriteError, QSerialPort::tr("Failed to write to port")));
440 }
441
442 return result;
443}
444
445qint64 QSerialPortPrivate::_writeToPortWithProgress(const char* data, qint64 maxSize, int timeout)
446{
447 const qint64 result = AndroidSerial::usePosixSerial()
448 ? _posixWriteWithProgress(data, maxSize, timeout)
449 : AndroidSerial::writeWithProgress(_deviceId, data, static_cast<int>(maxSize), timeout);
450 if (result < 0) {
451 qCWarning(AndroidSerialPortLog) << "Failed to write to port" << systemLocation;
452 setError(QSerialPortErrorInfo(QSerialPort::WriteError, QSerialPort::tr("Failed to write to port")));
453 }
454
455 return std::min(result, maxSize);
456}
457
458qint64 QSerialPortPrivate::writeData(const char* data, qint64 maxSize)
459{
460 if (!data || (maxSize <= 0)) {
461 qCWarning(AndroidSerialPortLog) << "Invalid data or size in writeData for device ID" << _deviceId;
462 setError(QSerialPortErrorInfo(QSerialPort::WriteError, QSerialPort::tr("Invalid data or size")));
463 return -1;
464 }
465
466 // Like desktop QSerialPort, writes are buffered and sent from the owner's event loop,
467 // waitForBytesWritten(), waitForReadyRead(), flush() or close().
468 writeBuffer.append(data, maxSize);
469 _scheduleWrite();
470 return maxSize;
471}
472
474{
475 return _writeDataOneShot();
476}
477
478bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
479{
481 return _posixClear(directions);
482 }
483
484 const bool input = directions & QSerialPort::Input;
485 const bool output = directions & QSerialPort::Output;
486
487 const bool result = AndroidSerial::purgeBuffers(_deviceId, input, output);
488 if (!result) {
489 qCWarning(AndroidSerialPortLog) << "Failed to purge buffers for device ID" << _deviceId;
490 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to purge buffers")));
491 }
492
493 return result;
494}
495
496QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
497{
499 return _posixPinoutSignals();
500 }
501
502 return AndroidSerial::getControlLines(_deviceId);
503}
504
506{
508 return _posixSetDataTerminalReady(set);
509 }
510
511 const bool result = AndroidSerial::setDataTerminalReady(_deviceId, set);
512 if (!result) {
513 qCWarning(AndroidSerialPortLog) << "Failed to set DTR for device ID" << _deviceId;
514 const auto dtrError = AndroidSerial::dataTerminalReadySupport(_deviceId) == 0
517 setError(QSerialPortErrorInfo(dtrError, QSerialPort::tr("Failed to set DTR")));
518 }
519
520 return result;
521}
522
524{
526 return _posixSetRequestToSend(set);
527 }
528
529 const bool result = AndroidSerial::setRequestToSend(_deviceId, set);
530 if (!result) {
531 qCWarning(AndroidSerialPortLog) << "Failed to set RTS for device ID" << _deviceId;
532 const auto rtsError = AndroidSerial::requestToSendSupport(_deviceId) == 0
535 setError(QSerialPortErrorInfo(rtsError, QSerialPort::tr("Failed to set RTS")));
536 }
537
538 return result;
539}
540
541bool QSerialPortPrivate::_setParameters(qint32 baudRate, QSerialPort::DataBits dataBits_,
543{
545 return _posixApplyPortSettings(baudRate, dataBits_, stopBits_, parity_, flowControl);
546 }
547
548 const bool result =
549 AndroidSerial::setParameters(_deviceId, baudRate, _dataBitsToAndroidDataBits(dataBits_),
550 _stopBitsToAndroidStopBits(stopBits_), _parityToAndroidParity(parity_));
551 if (!result) {
552 qCWarning(AndroidSerialPortLog) << "Failed to set Parameters for device ID" << _deviceId;
553 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set parameters")));
554 }
555
556 return result;
557}
558
563
564bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
565{
566 if (baudRate <= 0) {
567 qCWarning(AndroidSerialPortLog) << "Invalid baud rate value:" << baudRate;
568 setError(
569 QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Invalid baud rate value")));
570 return false;
571 }
572
573 if (directions != QSerialPort::AllDirections) {
574 qCWarning(AndroidSerialPortLog) << "Custom baud rate direction is unsupported:" << directions;
576 QSerialPort::tr("Custom baud rate direction is unsupported")));
577 return false;
578 }
579
580 const bool result = _setParameters(baudRate, dataBits, stopBits, parity);
581 if (result) {
582 inputBaudRate = outputBaudRate = baudRate;
583 } else {
584 qCWarning(AndroidSerialPortLog) << "Failed to set baud rate for device ID" << _deviceId;
585 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set baud rate")));
586 }
587
588 return result;
589}
590
591int QSerialPortPrivate::_dataBitsToAndroidDataBits(QSerialPort::DataBits dataBits_)
592{
593 switch (dataBits_) {
602 default:
603 qCWarning(AndroidSerialPortLog) << "Invalid Data Bits" << dataBits_;
604 return AndroidSerial::Data8; // Default to Data8
605 }
606}
607
609{
610 const bool result = _setParameters(inputBaudRate, dataBits_, stopBits, parity);
611 if (!result) {
612 qCWarning(AndroidSerialPortLog) << "Failed to set data bits for device ID" << _deviceId;
613 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set data bits")));
614 }
615
616 return result;
617}
618
619int QSerialPortPrivate::_parityToAndroidParity(QSerialPort::Parity parity_)
620{
621 switch (parity_) {
632 default:
633 qCWarning(AndroidSerialPortLog) << "Invalid parity type:" << parity_;
634 return AndroidSerial::NoParity; // Default to NoParity
635 }
636}
637
639{
640 const bool result = _setParameters(inputBaudRate, dataBits, stopBits, parity_);
641 if (!result) {
642 qCWarning(AndroidSerialPortLog) << "Failed to set parity for device ID" << _deviceId;
643 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set parity")));
644 }
645
646 return result;
647}
648
649int QSerialPortPrivate::_stopBitsToAndroidStopBits(QSerialPort::StopBits stopBits_)
650{
651 switch (stopBits_) {
658 default:
659 qCWarning(AndroidSerialPortLog) << "Invalid Stop Bits type:" << stopBits_;
660 return AndroidSerial::OneStop; // Default to OneStop
661 }
662}
663
665{
666 const bool result = _setParameters(inputBaudRate, dataBits, stopBits_, parity);
667 if (!result) {
668 qCWarning(AndroidSerialPortLog) << "Failed to set StopBits for device ID" << _deviceId;
669 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set StopBits")));
670 }
671
672 return result;
673}
674
675int QSerialPortPrivate::_flowControlToAndroidFlowControl(QSerialPort::FlowControl flowControl_)
676{
677 switch (flowControl_) {
684 default:
685 qCWarning(AndroidSerialPortLog) << "Invalid Flow Control type:" << flowControl_;
686 return AndroidSerial::NoFlowControl; // Default to NoFlowControl
687 }
688}
689
691{
693 return _posixApplyPortSettings(inputBaudRate, dataBits, stopBits, parity, flowControl_);
694 }
695
696 const bool result = AndroidSerial::setFlowControl(_deviceId, _flowControlToAndroidFlowControl(flowControl_));
697 if (!result) {
698 qCWarning(AndroidSerialPortLog) << "Failed to set Flow Control for device ID" << _deviceId;
699 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set Flow Control")));
700 }
701
702 return result;
703}
704
706{
708 return _posixSetBreakEnabled(set);
709 }
710
711 const bool result = AndroidSerial::setBreak(_deviceId, set);
712 if (!result) {
713 setError(QSerialPortErrorInfo(QSerialPort::UnknownError, QSerialPort::tr("Failed to set Break Enabled")));
714 }
715
716 return result;
717}
718
719static constexpr qint32 kStandardBaudRates[] = {
720 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
721 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
722 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000,
723};
724
726{
727 return QList<qint32>(std::begin(kStandardBaudRates), std::end(kStandardBaudRates));
728}
729
730QSerialPort::Handle QSerialPort::handle() const
731{
732 Q_D(const QSerialPort);
733 return d->descriptor;
734}
735
736QT_END_NAMESPACE
#define QGC_LOGGING_CATEGORY(name, categoryStr)
bool waitForBytesWritten(int msec)
void setError(const QSerialPortErrorInfo &errorInfo)
bool setDataTerminalReady(bool set)
bool setStopBits(QSerialPort::StopBits stopBits)
bool setFlowControl(QSerialPort::FlowControl flowControl)
QSerialPort::PinoutSignals pinoutSignals()
bool clear(QSerialPort::Directions directions)
bool setDataBits(QSerialPort::DataBits dataBits)
static QList< qint32 > standardBaudRates()
qint64 writeData(const char *data, qint64 maxSize)
bool setRequestToSend(bool set)
void exceptionArrived(const QString &ex)
bool setParity(QSerialPort::Parity parity)
void newDataArrived(const char *bytes, int length)
Provides functions to access serial ports.
Definition qserialport.h:17
DataBits
This enum describes the number of data bits used.
Definition qserialport.h:60
Parity
This enum describes the parity scheme used.
Definition qserialport.h:69
@ UnsupportedOperationError
StopBits
This enum describes the number of stop bits used.
Definition qserialport.h:79
FlowControl
This enum describes the flow control used.
Definition qserialport.h:87
Handle handle() const
int open(const QString &portName, QSerialPortPrivate *classPtr)
void registerPointer(QSerialPortPrivate *ptr)
int getDeviceHandle(int deviceId)
int writeWithProgress(int deviceId, const char *data, int length, int timeout)
Returns bytes written, fewer than length on timeout, or -1 on error. A zero timeout waits without lim...
void unregisterPointer(QSerialPortPrivate *ptr)
bool usePosixSerial()
bool setDataTerminalReady(int deviceId, bool set)
int requestToSendSupport(int deviceId)
bool setParameters(int deviceId, int baudRate, int dataBits, int stopBits, int parity)
bool startReadThread(int deviceId)
QSerialPort::PinoutSignals getControlLines(int deviceId)
bool setRequestToSend(int deviceId, bool set)
bool purgeBuffers(int deviceId, bool input, bool output)
bool readThreadRunning(int deviceId)
bool close(int deviceId)
bool stopReadThread(int deviceId)
int dataTerminalReadySupport(int deviceId)
bool setFlowControl(int deviceId, int flowControl)
bool setBreak(int deviceId, bool set)
bool write(QByteArray &buffer, const GeoTagData &geotag)
Definition ExifParser.cc:32
static constexpr qint32 kStandardBaudRates[]
constexpr int INVALID_DEVICE_ID