6#include <QtCore/QMetaObject>
7#include <QtCore/QPointer>
8#include <QtCore/QScopeGuard>
20 return _posixOpen(mode);
23 qCDebug(AndroidSerialPortLog) <<
"Opening" << systemLocation;
30 qCWarning(AndroidSerialPortLog) <<
"Error opening" << systemLocation;
36 if (descriptor == -1) {
37 qCWarning(AndroidSerialPortLog) <<
"Failed to get device handle for" << systemLocation;
43 if (!_setParameters(inputBaudRate, dataBits, stopBits, parity)) {
44 qCWarning(AndroidSerialPortLog) <<
"Failed to set serial port parameters for" << systemLocation;
49 if (!setFlowControl(flowControl)) {
50 qCWarning(AndroidSerialPortLog) <<
"Failed to set serial port flow control for" << systemLocation;
55 if (mode & QIODevice::ReadOnly) {
56 if (!startAsyncRead()) {
57 qCWarning(AndroidSerialPortLog) <<
"Failed to start async read for" << systemLocation;
61 }
else if (mode & QIODevice::WriteOnly) {
62 if (!_stopAsyncRead()) {
63 qCWarning(AndroidSerialPortLog) <<
"Failed to stop async read for" << systemLocation;
87 QMutexLocker locker(&_readMutex);
89 _pendingDataOffset = 0;
90 _readyReadPending.store(
false);
91 _bufferBytesEstimate.store(0, std::memory_order_relaxed);
96 qCWarning(AndroidSerialPortLog) <<
"Failed to close device with ID" << _deviceId;
109 qCWarning(AndroidSerialPortLog) <<
"Exception arrived on device ID" << _deviceId <<
":" << ex;
116 return _posixStartAsyncRead();
122 qCWarning(AndroidSerialPortLog) <<
"Failed to start async read thread for device ID" << _deviceId;
130 _scheduleReadyRead();
135bool QSerialPortPrivate::_stopAsyncRead()
138 return _posixStopAsyncRead();
146 qCWarning(AndroidSerialPortLog) <<
"Failed to stop async read thread for device ID" << _deviceId;
154qint64 QSerialPortPrivate::_drainPendingDataLocked(qint64 maxBytes)
156 const qsizetype pendingSize = _pendingSizeLocked();
157 if (pendingSize <= 0) {
158 _pendingData.clear();
159 _pendingDataOffset = 0;
163 qint64 toDrain = pendingSize;
165 toDrain = qMin(toDrain, maxBytes);
172 buffer.append(_pendingData.constData() + _pendingDataOffset, toDrain);
173 _pendingDataOffset +=
static_cast<qsizetype
>(toDrain);
175 if (_pendingDataOffset >= _pendingData.size()) {
176 _pendingData.clear();
177 _pendingDataOffset = 0;
181 constexpr qsizetype kCompactThreshold = 4096;
182 if (_pendingDataOffset >= kCompactThreshold && (_pendingDataOffset * 2) >= _pendingData.size()) {
183 _compactPendingDataLocked();
187 _bufferBytesEstimate.store(buffer.size(), std::memory_order_relaxed);
191qsizetype QSerialPortPrivate::_pendingSizeLocked()
const
193 return qMax<qsizetype>(0, _pendingData.size() - _pendingDataOffset);
196void QSerialPortPrivate::_compactPendingDataLocked()
198 if (_pendingDataOffset <= 0) {
202 if (_pendingDataOffset >= _pendingData.size()) {
203 _pendingData.clear();
204 _pendingDataOffset = 0;
208 _pendingData.remove(0, _pendingDataOffset);
209 _pendingDataOffset = 0;
216 qint64 droppedBytes = 0;
218 QMutexLocker locker(&_readMutex);
219 int bytesToRead = length;
221 const qint64 totalBuffered = _pendingSizeLocked() + _bufferBytesEstimate.load(std::memory_order_relaxed);
223 if (bytesToRead > headroom) {
224 bytesToRead =
static_cast<int>(qMax(qint64(0), headroom));
225 droppedBytes =
static_cast<qint64
>(length - bytesToRead);
229 if (bytesToRead > 0) {
230 constexpr qsizetype kCompactBeforeAppendThreshold = 8192;
231 if (_pendingDataOffset >= kCompactBeforeAppendThreshold) {
232 _compactPendingDataLocked();
234 _pendingData.append(bytes, bytesToRead);
235 _readWaitCondition.wakeAll();
239 if (droppedBytes > 0) {
240 qCWarning(AndroidSerialPortLog) <<
"Read buffer full, dropping" << droppedBytes <<
"bytes";
243 if (bytesToRead <= 0) {
247 _scheduleReadyRead();
250void QSerialPortPrivate::_scheduleReadyRead()
254 if (!_readyReadPending.exchange(
true)) {
255 QPointer<QSerialPort> guard(q);
256 QMetaObject::invokeMethod(
259 if (!guard || !guard->isOpen()) {
262 _readyReadPending.store(false);
266 QMutexLocker locker(&_readMutex);
267 if (_pendingSizeLocked() <= 0) {
268 _readyReadPending.store(
false);
275 (void)_drainPendingDataLocked(canAccept);
278 (void)_drainPendingDataLocked();
284 const bool more = (_pendingSizeLocked() > 0);
285 _readyReadPending.store(
false);
287 _readWaitCondition.wakeAll();
290 emit guard->readyRead();
293 _scheduleReadyRead();
296 Qt::QueuedConnection);
300bool QSerialPortPrivate::waitForReadyRead(
int msecs)
303 const QDeadlineTimer deadline(msecs);
305 (void) _writeDataOneShot(msecs);
308 return _posixWaitForReadyRead(
static_cast<int>(deadline.remainingTime()));
311 QMutexLocker locker(&_readMutex);
312 if (!buffer.isEmpty()) {
316 if (_pendingSizeLocked() > 0) {
317 (void)_drainPendingDataLocked();
321 while (buffer.isEmpty() && (_pendingSizeLocked() <= 0)) {
322 if (!_readWaitCondition.wait(&_readMutex, deadline)) {
326 if (!buffer.isEmpty()) {
330 if (_pendingSizeLocked() > 0) {
331 (void)_drainPendingDataLocked();
337 qCDebug(AndroidSerialPortLog) <<
"Timeout while waiting for ready read on device ID" << _deviceId;
345 if (writeBuffer.isEmpty()) {
349 return _writeDataOneShot(msecs);
352int QSerialPortPrivate::_writeTimeoutMs(
const QDeadlineTimer& deadline)
355 if (deadline.isForever()) {
358 return static_cast<int>(std::clamp<qint64>(deadline.remainingTime(), 1, std::numeric_limits<int>::max()));
361bool QSerialPortPrivate::_writeDataOneShot(
int msecs)
365 if (writeBuffer.isEmpty()) {
369 const QDeadlineTimer deadline(msecs);
371 bool complete =
true;
372 while (!writeBuffer.isEmpty()) {
373 const qint64 blockSize = writeBuffer.nextDataBlockSize();
374 const qint64 result = _writeToPortWithProgress(writeBuffer.readPointer(), blockSize, _writeTimeoutMs(deadline));
380 writeBuffer.free(result);
382 if (result < blockSize) {
383 qCDebug(AndroidSerialPortLog)
384 <<
"Write timed out on device ID" << _deviceId <<
"after" << written <<
"bytes";
392 emit q->bytesWritten(written);
398void QSerialPortPrivate::_scheduleWrite()
402 if (std::exchange(_writePending,
true)) {
406 QPointer<QSerialPort> guard(q);
407 QMetaObject::invokeMethod(
413 _writePending =
false;
414 if (!guard->isOpen() || writeBuffer.isEmpty()) {
418 const qint64 pending = writeBuffer.size();
419 (void) _writeDataOneShot();
421 if (guard && guard->isOpen() && !writeBuffer.isEmpty() && writeBuffer.size() < pending) {
425 Qt::QueuedConnection);
428qint64 QSerialPortPrivate::_writeToPort(
const char* data, qint64 maxSize,
int timeout,
bool async)
431 qCWarning(AndroidSerialPortLog) <<
"Async write is not supported by the POSIX backend; writing synchronously";
435 ? _posixWrite(data, maxSize, timeout)
438 qCWarning(AndroidSerialPortLog) <<
"Failed to write to port" <<
systemLocation;
445qint64 QSerialPortPrivate::_writeToPortWithProgress(
const char* data, qint64 maxSize,
int timeout)
448 ? _posixWriteWithProgress(data, maxSize, timeout)
451 qCWarning(AndroidSerialPortLog) <<
"Failed to write to port" <<
systemLocation;
455 return std::min(result, maxSize);
460 if (!data || (maxSize <= 0)) {
461 qCWarning(AndroidSerialPortLog) <<
"Invalid data or size in writeData for device ID" << _deviceId;
468 writeBuffer.append(data, maxSize);
475 return _writeDataOneShot();
481 return _posixClear(directions);
489 qCWarning(AndroidSerialPortLog) <<
"Failed to purge buffers for device ID" << _deviceId;
499 return _posixPinoutSignals();
508 return _posixSetDataTerminalReady(set);
513 qCWarning(AndroidSerialPortLog) <<
"Failed to set DTR for device ID" << _deviceId;
526 return _posixSetRequestToSend(set);
531 qCWarning(AndroidSerialPortLog) <<
"Failed to set RTS for device ID" << _deviceId;
545 return _posixApplyPortSettings(baudRate, dataBits_, stopBits_, parity_, flowControl);
550 _stopBitsToAndroidStopBits(stopBits_), _parityToAndroidParity(parity_));
552 qCWarning(AndroidSerialPortLog) <<
"Failed to set Parameters for device ID" << _deviceId;
567 qCWarning(AndroidSerialPortLog) <<
"Invalid baud rate value:" << baudRate;
574 qCWarning(AndroidSerialPortLog) <<
"Custom baud rate direction is unsupported:" << directions;
576 QSerialPort::tr(
"Custom baud rate direction is unsupported")));
580 const bool result = _setParameters(baudRate, dataBits, stopBits, parity);
584 qCWarning(AndroidSerialPortLog) <<
"Failed to set baud rate for device ID" << _deviceId;
603 qCWarning(AndroidSerialPortLog) <<
"Invalid Data Bits" << dataBits_;
610 const bool result = _setParameters(
inputBaudRate, dataBits_, stopBits, parity);
612 qCWarning(AndroidSerialPortLog) <<
"Failed to set data bits for device ID" << _deviceId;
633 qCWarning(AndroidSerialPortLog) <<
"Invalid parity type:" << parity_;
640 const bool result = _setParameters(
inputBaudRate, dataBits, stopBits, parity_);
642 qCWarning(AndroidSerialPortLog) <<
"Failed to set parity for device ID" << _deviceId;
659 qCWarning(AndroidSerialPortLog) <<
"Invalid Stop Bits type:" << stopBits_;
666 const bool result = _setParameters(
inputBaudRate, dataBits, stopBits_, parity);
668 qCWarning(AndroidSerialPortLog) <<
"Failed to set StopBits for device ID" << _deviceId;
677 switch (flowControl_) {
685 qCWarning(AndroidSerialPortLog) <<
"Invalid Flow Control type:" << flowControl_;
693 return _posixApplyPortSettings(
inputBaudRate, dataBits, stopBits, parity, flowControl_);
698 qCWarning(AndroidSerialPortLog) <<
"Failed to set Flow Control for device ID" << _deviceId;
708 return _posixSetBreakEnabled(set);
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,
733 return d->descriptor;
#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)
bool setBreakEnabled(bool set)
Provides functions to access serial ports.
DataBits
This enum describes the number of data bits used.
Parity
This enum describes the parity scheme used.
@ UnsupportedOperationError
StopBits
This enum describes the number of stop bits used.
FlowControl
This enum describes the flow control used.
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 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 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)
static constexpr qint32 kStandardBaudRates[]
constexpr int INVALID_DEVICE_ID