1#include <QtCore/QMetaObject>
2#include <QtCore/QPointer>
3#include <QtCore/QScopeGuard>
17 return _posixOpen(mode);
20 qCDebug(AndroidSerialPortLog) <<
"Opening" << systemLocation;
27 qCWarning(AndroidSerialPortLog) <<
"Error opening" << systemLocation;
33 if (descriptor == -1) {
34 qCWarning(AndroidSerialPortLog) <<
"Failed to get device handle for" << systemLocation;
40 if (!_setParameters(inputBaudRate, dataBits, stopBits, parity)) {
41 qCWarning(AndroidSerialPortLog) <<
"Failed to set serial port parameters for" << systemLocation;
46 if (!setFlowControl(flowControl)) {
47 qCWarning(AndroidSerialPortLog) <<
"Failed to set serial port flow control for" << systemLocation;
52 if (mode & QIODevice::ReadOnly) {
53 if (!startAsyncRead()) {
54 qCWarning(AndroidSerialPortLog) <<
"Failed to start async read for" << systemLocation;
58 }
else if (mode & QIODevice::WriteOnly) {
59 if (!_stopAsyncRead()) {
60 qCWarning(AndroidSerialPortLog) <<
"Failed to stop async read for" << systemLocation;
84 QMutexLocker locker(&_readMutex);
86 _pendingDataOffset = 0;
87 _readyReadPending.store(
false);
88 _bufferBytesEstimate.store(0, std::memory_order_relaxed);
93 qCWarning(AndroidSerialPortLog) <<
"Failed to close device with ID" << _deviceId;
106 qCWarning(AndroidSerialPortLog) <<
"Exception arrived on device ID" << _deviceId <<
":" << ex;
113 return _posixStartAsyncRead();
119 qCWarning(AndroidSerialPortLog) <<
"Failed to start async read thread for device ID" << _deviceId;
127 _scheduleReadyRead();
132bool QSerialPortPrivate::_stopAsyncRead()
135 return _posixStopAsyncRead();
143 qCWarning(AndroidSerialPortLog) <<
"Failed to stop async read thread for device ID" << _deviceId;
151qint64 QSerialPortPrivate::_drainPendingDataLocked(qint64 maxBytes)
153 const qsizetype pendingSize = _pendingSizeLocked();
154 if (pendingSize <= 0) {
155 _pendingData.clear();
156 _pendingDataOffset = 0;
160 qint64 toDrain = pendingSize;
162 toDrain = qMin(toDrain, maxBytes);
169 buffer.append(_pendingData.constData() + _pendingDataOffset, toDrain);
170 _pendingDataOffset +=
static_cast<qsizetype
>(toDrain);
172 if (_pendingDataOffset >= _pendingData.size()) {
173 _pendingData.clear();
174 _pendingDataOffset = 0;
178 constexpr qsizetype kCompactThreshold = 4096;
179 if (_pendingDataOffset >= kCompactThreshold && (_pendingDataOffset * 2) >= _pendingData.size()) {
180 _compactPendingDataLocked();
184 _bufferBytesEstimate.store(buffer.size(), std::memory_order_relaxed);
188qsizetype QSerialPortPrivate::_pendingSizeLocked()
const
190 return qMax<qsizetype>(0, _pendingData.size() - _pendingDataOffset);
193void QSerialPortPrivate::_compactPendingDataLocked()
195 if (_pendingDataOffset <= 0) {
199 if (_pendingDataOffset >= _pendingData.size()) {
200 _pendingData.clear();
201 _pendingDataOffset = 0;
205 _pendingData.remove(0, _pendingDataOffset);
206 _pendingDataOffset = 0;
213 qint64 droppedBytes = 0;
215 QMutexLocker locker(&_readMutex);
216 int bytesToRead = length;
218 const qint64 totalBuffered = _pendingSizeLocked() + _bufferBytesEstimate.load(std::memory_order_relaxed);
220 if (bytesToRead > headroom) {
221 bytesToRead =
static_cast<int>(qMax(qint64(0), headroom));
222 droppedBytes =
static_cast<qint64
>(length - bytesToRead);
226 if (bytesToRead > 0) {
227 constexpr qsizetype kCompactBeforeAppendThreshold = 8192;
228 if (_pendingDataOffset >= kCompactBeforeAppendThreshold) {
229 _compactPendingDataLocked();
231 _pendingData.append(bytes, bytesToRead);
232 _readWaitCondition.wakeAll();
236 if (droppedBytes > 0) {
237 qCWarning(AndroidSerialPortLog) <<
"Read buffer full, dropping" << droppedBytes <<
"bytes";
240 if (bytesToRead <= 0) {
244 _scheduleReadyRead();
247void QSerialPortPrivate::_scheduleReadyRead()
251 if (!_readyReadPending.exchange(
true)) {
252 QPointer<QSerialPort> guard(q);
253 QMetaObject::invokeMethod(
256 if (!guard || !guard->isOpen()) {
259 _readyReadPending.store(false);
263 QMutexLocker locker(&_readMutex);
264 if (_pendingSizeLocked() <= 0) {
265 _readyReadPending.store(
false);
272 (void)_drainPendingDataLocked(canAccept);
275 (void)_drainPendingDataLocked();
281 const bool more = (_pendingSizeLocked() > 0);
282 _readyReadPending.store(
false);
284 _readWaitCondition.wakeAll();
287 emit guard->readyRead();
290 _scheduleReadyRead();
293 Qt::QueuedConnection);
297bool QSerialPortPrivate::waitForReadyRead(
int msecs)
300 return _posixWaitForReadyRead(msecs);
303 QMutexLocker locker(&_readMutex);
304 if (!buffer.isEmpty()) {
308 if (_pendingSizeLocked() > 0) {
309 (void)_drainPendingDataLocked();
313 QDeadlineTimer deadline(msecs);
314 while (buffer.isEmpty() && (_pendingSizeLocked() <= 0)) {
315 if (!_readWaitCondition.wait(&_readMutex, deadline)) {
319 if (!buffer.isEmpty()) {
323 if (_pendingSizeLocked() > 0) {
324 (void)_drainPendingDataLocked();
330 qCWarning(AndroidSerialPortLog) <<
"Timeout while waiting for ready read on device ID" << _deviceId;
338 const bool result = _writeDataOneShot(msecs);
340 qCWarning(AndroidSerialPortLog) <<
"Timeout while waiting for bytes written on device ID" << _deviceId;
342 QSerialPort::tr(
"Timeout while waiting for bytes written")));
348bool QSerialPortPrivate::_writeDataOneShot(
int msecs)
350 if (writeBuffer.isEmpty()) {
354 qint64 pendingBytesWritten = 0;
356 while (!writeBuffer.isEmpty()) {
357 const char* dataPtr = writeBuffer.readPointer();
358 const qint64 dataSize = writeBuffer.nextDataBlockSize();
360 const qint64 written = _writeToPort(dataPtr, dataSize, msecs);
362 qCWarning(AndroidSerialPortLog) <<
"Failed to write data one shot on device ID" << _deviceId;
367 writeBuffer.free(written);
368 pendingBytesWritten += written;
371 const bool result = (pendingBytesWritten > 0);
374 emit q->bytesWritten(pendingBytesWritten);
380qint64 QSerialPortPrivate::_writeToPort(
const char* data, qint64 maxSize,
int timeout,
bool async)
383 qCWarning(AndroidSerialPortLog) <<
"Async write is not supported by the POSIX backend; writing synchronously";
387 ? _posixWrite(data, maxSize, timeout)
390 qCWarning(AndroidSerialPortLog) <<
"Failed to write to port" <<
systemLocation;
399 if (!data || (maxSize <= 0)) {
400 qCWarning(AndroidSerialPortLog) <<
"Invalid data or size in writeData for device ID" << _deviceId;
405 return _writeToPort(data, maxSize);
410 const bool result = _writeDataOneShot();
412 qCWarning(AndroidSerialPortLog) <<
"Flush operation failed for device ID" << _deviceId;
422 return _posixClear(directions);
430 qCWarning(AndroidSerialPortLog) <<
"Failed to purge buffers for device ID" << _deviceId;
440 return _posixPinoutSignals();
449 return _posixSetDataTerminalReady(set);
454 qCWarning(AndroidSerialPortLog) <<
"Failed to set DTR for device ID" << _deviceId;
464 return _posixSetRequestToSend(set);
469 qCWarning(AndroidSerialPortLog) <<
"Failed to set RTS for device ID" << _deviceId;
480 return _posixApplyPortSettings(baudRate, dataBits_, stopBits_, parity_, flowControl);
485 _stopBitsToAndroidStopBits(stopBits_), _parityToAndroidParity(parity_));
487 qCWarning(AndroidSerialPortLog) <<
"Failed to set Parameters for device ID" << _deviceId;
502 qCWarning(AndroidSerialPortLog) <<
"Invalid baud rate value:" << baudRate;
509 qCWarning(AndroidSerialPortLog) <<
"Custom baud rate direction is unsupported:" << directions;
511 QSerialPort::tr(
"Custom baud rate direction is unsupported")));
515 const bool result = _setParameters(baudRate, dataBits, stopBits, parity);
519 qCWarning(AndroidSerialPortLog) <<
"Failed to set baud rate for device ID" << _deviceId;
538 qCWarning(AndroidSerialPortLog) <<
"Invalid Data Bits" << dataBits_;
545 const bool result = _setParameters(
inputBaudRate, dataBits_, stopBits, parity);
547 qCWarning(AndroidSerialPortLog) <<
"Failed to set data bits for device ID" << _deviceId;
568 qCWarning(AndroidSerialPortLog) <<
"Invalid parity type:" << parity_;
575 const bool result = _setParameters(
inputBaudRate, dataBits, stopBits, parity_);
577 qCWarning(AndroidSerialPortLog) <<
"Failed to set parity for device ID" << _deviceId;
594 qCWarning(AndroidSerialPortLog) <<
"Invalid Stop Bits type:" << stopBits_;
601 const bool result = _setParameters(
inputBaudRate, dataBits, stopBits_, parity);
603 qCWarning(AndroidSerialPortLog) <<
"Failed to set StopBits for device ID" << _deviceId;
612 switch (flowControl_) {
620 qCWarning(AndroidSerialPortLog) <<
"Invalid Flow Control type:" << flowControl_;
628 return _posixApplyPortSettings(
inputBaudRate, dataBits, stopBits, parity, flowControl_);
633 qCWarning(AndroidSerialPortLog) <<
"Failed to set Flow Control for device ID" << _deviceId;
643 return _posixSetBreakEnabled(set);
655 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
656 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000,
657 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000,
668 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)
void unregisterPointer(QSerialPortPrivate *ptr)
bool setDataTerminalReady(int deviceId, bool set)
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)
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