blob: c0061fc98728d1d0f412070152703f040d5ba2a0 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2012 Denis Shienkov <denis.shienkov@gmail.com>
** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2012 Andre Hartmann <aha_1980@gmx.de>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtSerialPort module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qserialport_p.h"
#include "qtntdll_p.h"
#include <QtCore/qcoreevent.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qmutex.h>
#include <QtCore/qtimer.h>
#include <QtCore/qvector.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
static inline void qt_set_common_props(DCB *dcb)
{
dcb->fBinary = TRUE;
dcb->fAbortOnError = FALSE;
dcb->fNull = FALSE;
dcb->fErrorChar = FALSE;
if (dcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
dcb->fDtrControl = DTR_CONTROL_DISABLE;
if (dcb->fRtsControl != RTS_CONTROL_HANDSHAKE)
dcb->fRtsControl = RTS_CONTROL_DISABLE;
}
static inline void qt_set_baudrate(DCB *dcb, qint32 baudrate)
{
dcb->BaudRate = baudrate;
}
static inline void qt_set_databits(DCB *dcb, QSerialPort::DataBits databits)
{
dcb->ByteSize = databits;
}
static inline void qt_set_parity(DCB *dcb, QSerialPort::Parity parity)
{
dcb->fParity = TRUE;
switch (parity) {
case QSerialPort::NoParity:
dcb->Parity = NOPARITY;
dcb->fParity = FALSE;
break;
case QSerialPort::OddParity:
dcb->Parity = ODDPARITY;
break;
case QSerialPort::EvenParity:
dcb->Parity = EVENPARITY;
break;
case QSerialPort::MarkParity:
dcb->Parity = MARKPARITY;
break;
case QSerialPort::SpaceParity:
dcb->Parity = SPACEPARITY;
break;
default:
dcb->Parity = NOPARITY;
dcb->fParity = FALSE;
break;
}
}
static inline void qt_set_stopbits(DCB *dcb, QSerialPort::StopBits stopbits)
{
switch (stopbits) {
case QSerialPort::OneStop:
dcb->StopBits = ONESTOPBIT;
break;
case QSerialPort::OneAndHalfStop:
dcb->StopBits = ONE5STOPBITS;
break;
case QSerialPort::TwoStop:
dcb->StopBits = TWOSTOPBITS;
break;
default:
dcb->StopBits = ONESTOPBIT;
break;
}
}
static inline void qt_set_flowcontrol(DCB *dcb, QSerialPort::FlowControl flowcontrol)
{
dcb->fInX = FALSE;
dcb->fOutX = FALSE;
dcb->fOutxCtsFlow = FALSE;
if (dcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
dcb->fRtsControl = RTS_CONTROL_DISABLE;
switch (flowcontrol) {
case QSerialPort::NoFlowControl:
break;
case QSerialPort::SoftwareControl:
dcb->fInX = TRUE;
dcb->fOutX = TRUE;
break;
case QSerialPort::HardwareControl:
dcb->fOutxCtsFlow = TRUE;
dcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
default:
break;
}
}
// Translate NT-callbacks to Win32 callbacks.
static VOID WINAPI qt_apc_routine(
PVOID context,
PIO_STATUS_BLOCK ioStatusBlock,
DWORD reserved)
{
Q_UNUSED(reserved);
const DWORD errorCode = ::RtlNtStatusToDosError(ioStatusBlock->Status);
const DWORD bytesTransfered = NT_SUCCESS(ioStatusBlock->Status)
? DWORD(ioStatusBlock->Information) : 0;
const LPOVERLAPPED overlapped = CONTAINING_RECORD(ioStatusBlock,
OVERLAPPED, Internal);
(reinterpret_cast<LPOVERLAPPED_COMPLETION_ROUTINE>(context))
(errorCode, bytesTransfered, overlapped);
}
// Alertable analog of DeviceIoControl function.
static BOOL qt_device_io_control_ex(
HANDLE deviceHandle,
DWORD ioControlCode,
LPVOID inputBuffer,
DWORD inputBufferSize,
LPVOID outputBuffer,
DWORD outputBufferSize,
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
{
const auto ioStatusBlock = reinterpret_cast<PIO_STATUS_BLOCK>(
&overlapped->Internal);
ioStatusBlock->Status = STATUS_PENDING;
const NTSTATUS status = ::NtDeviceIoControlFile(
deviceHandle,
nullptr,
qt_apc_routine,
reinterpret_cast<PVOID>(completionRoutine),
ioStatusBlock,
ioControlCode,
inputBuffer,
inputBufferSize,
outputBuffer,
outputBufferSize);
if (!NT_SUCCESS(status)) {
::SetLastError(::RtlNtStatusToDosError(status));
return false;
}
return true;
}
// Alertable analog of WaitCommEvent function.
static BOOL qt_wait_comm_event_ex(
HANDLE deviceHandle,
LPDWORD eventsMask,
LPOVERLAPPED overlapped,
LPOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
{
return qt_device_io_control_ex(
deviceHandle,
IOCTL_SERIAL_WAIT_ON_MASK,
nullptr,
0,
eventsMask,
sizeof(DWORD),
overlapped,
completionRoutine);
}
struct RuntimeHelper
{
QLibrary ntLibrary;
QBasicMutex mutex;
};
Q_GLOBAL_STATIC(RuntimeHelper, helper)
class Overlapped final : public OVERLAPPED
{
Q_DISABLE_COPY(Overlapped)
public:
explicit Overlapped(QSerialPortPrivate *d);
void clear();
QSerialPortPrivate *dptr = nullptr;
};
Overlapped::Overlapped(QSerialPortPrivate *d)
: dptr(d)
{
}
void Overlapped::clear()
{
::ZeroMemory(this, sizeof(OVERLAPPED));
}
bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
{
{
QMutexLocker locker(&helper()->mutex);
static bool symbolsResolved = resolveNtdllSymbols(&helper()->ntLibrary);
if (!symbolsResolved) {
setError(QSerialPortErrorInfo(QSerialPort::OpenError,
helper()->ntLibrary.errorString()));
return false;
}
}
DWORD desiredAccess = 0;
if (mode & QIODevice::ReadOnly)
desiredAccess |= GENERIC_READ;
if (mode & QIODevice::WriteOnly)
desiredAccess |= GENERIC_WRITE;
handle = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()),
desiredAccess, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
setError(getSystemError());
return false;
}
if (initialize(mode))
return true;
::CloseHandle(handle);
return false;
}
void QSerialPortPrivate::close()
{
delete startAsyncWriteTimer;
startAsyncWriteTimer = nullptr;
if (communicationStarted) {
communicationCompletionOverlapped->dptr = nullptr;
::CancelIoEx(handle, communicationCompletionOverlapped);
// The object will be deleted in the I/O callback.
communicationCompletionOverlapped = nullptr;
communicationStarted = false;
} else {
delete communicationCompletionOverlapped;
communicationCompletionOverlapped = nullptr;
}
if (readStarted) {
readCompletionOverlapped->dptr = nullptr;
::CancelIoEx(handle, readCompletionOverlapped);
// The object will be deleted in the I/O callback.
readCompletionOverlapped = nullptr;
readStarted = false;
} else {
delete readCompletionOverlapped;
readCompletionOverlapped = nullptr;
};
if (writeStarted) {
writeCompletionOverlapped->dptr = nullptr;
::CancelIoEx(handle, writeCompletionOverlapped);
// The object will be deleted in the I/O callback.
writeCompletionOverlapped = nullptr;
writeStarted = false;
} else {
delete writeCompletionOverlapped;
writeCompletionOverlapped = nullptr;
}
readBytesTransferred = 0;
writeBytesTransferred = 0;
writeBuffer.clear();
if (settingsRestoredOnClose) {
::SetCommState(handle, &restoredDcb);
::SetCommTimeouts(handle, &restoredCommTimeouts);
}
::CloseHandle(handle);
handle = INVALID_HANDLE_VALUE;
}
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals()
{
DWORD modemStat = 0;
if (!::GetCommModemStatus(handle, &modemStat)) {
setError(getSystemError());
return QSerialPort::NoSignal;
}
QSerialPort::PinoutSignals ret = QSerialPort::NoSignal;
if (modemStat & MS_CTS_ON)
ret |= QSerialPort::ClearToSendSignal;
if (modemStat & MS_DSR_ON)
ret |= QSerialPort::DataSetReadySignal;
if (modemStat & MS_RING_ON)
ret |= QSerialPort::RingIndicatorSignal;
if (modemStat & MS_RLSD_ON)
ret |= QSerialPort::DataCarrierDetectSignal;
DWORD bytesReturned = 0;
if (!::DeviceIoControl(handle, IOCTL_SERIAL_GET_DTRRTS, nullptr, 0,
&modemStat, sizeof(modemStat),
&bytesReturned, nullptr)) {
setError(getSystemError());
return ret;
}
if (modemStat & SERIAL_DTR_STATE)
ret |= QSerialPort::DataTerminalReadySignal;
if (modemStat & SERIAL_RTS_STATE)
ret |= QSerialPort::RequestToSendSignal;
return ret;
}
bool QSerialPortPrivate::setDataTerminalReady(bool set)
{
if (!::EscapeCommFunction(handle, set ? SETDTR : CLRDTR)) {
setError(getSystemError());
return false;
}
DCB dcb;
if (!getDcb(&dcb))
return false;
dcb.fDtrControl = set ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE;
return setDcb(&dcb);
}
bool QSerialPortPrivate::setRequestToSend(bool set)
{
if (!::EscapeCommFunction(handle, set ? SETRTS : CLRRTS)) {
setError(getSystemError());
return false;
}
DCB dcb;
if (!getDcb(&dcb))
return false;
dcb.fRtsControl = set ? RTS_CONTROL_ENABLE : RTS_CONTROL_DISABLE;
return setDcb(&dcb);
}
bool QSerialPortPrivate::flush()
{
return _q_startAsyncWrite();
}
bool QSerialPortPrivate::clear(QSerialPort::Directions directions)
{
DWORD flags = 0;
if (directions & QSerialPort::Input)
flags |= PURGE_RXABORT | PURGE_RXCLEAR;
if (directions & QSerialPort::Output)
flags |= PURGE_TXABORT | PURGE_TXCLEAR;
if (!::PurgeComm(handle, flags)) {
setError(getSystemError());
return false;
}
// We need start async read because a reading can be stalled. Since the
// PurgeComm can abort of current reading sequence, or a port is in hardware
// flow control mode, or a port has a limited read buffer size.
if (directions & QSerialPort::Input)
startAsyncCommunication();
return true;
}
bool QSerialPortPrivate::sendBreak(int duration)
{
if (!setBreakEnabled(true))
return false;
::Sleep(duration);
if (!setBreakEnabled(false))
return false;
return true;
}
bool QSerialPortPrivate::setBreakEnabled(bool set)
{
if (set ? !::SetCommBreak(handle) : !::ClearCommBreak(handle)) {
setError(getSystemError());
return false;
}
return true;
}
bool QSerialPortPrivate::waitForReadyRead(int msecs)
{
if (!writeStarted && !_q_startAsyncWrite())
return false;
QDeadlineTimer deadline(msecs);
do {
if (readBytesTransferred <= 0) {
const qint64 remaining = deadline.remainingTime();
const DWORD result = ::SleepEx(
remaining == -1 ? INFINITE : DWORD(remaining),
TRUE);
if (result != WAIT_IO_COMPLETION)
continue;
}
if (readBytesTransferred > 0) {
readBytesTransferred = 0;
return true;
}
} while (!deadline.hasExpired());
setError(getSystemError(WAIT_TIMEOUT));
return false;
}
bool QSerialPortPrivate::waitForBytesWritten(int msecs)
{
if (writeBuffer.isEmpty() && writeChunkBuffer.isEmpty())
return false;
if (!writeStarted && !_q_startAsyncWrite())
return false;
QDeadlineTimer deadline(msecs);
do {
if (writeBytesTransferred <= 0) {
const qint64 remaining = deadline.remainingTime();
const DWORD result = ::SleepEx(
remaining == -1 ? INFINITE : DWORD(remaining),
TRUE);
if (result != WAIT_IO_COMPLETION)
continue;
}
if (writeBytesTransferred > 0) {
writeBytesTransferred = 0;
return true;
}
} while (!deadline.hasExpired());
setError(getSystemError(WAIT_TIMEOUT));
return false;
}
bool QSerialPortPrivate::setBaudRate()
{
return setBaudRate(inputBaudRate, QSerialPort::AllDirections);
}
bool QSerialPortPrivate::setBaudRate(qint32 baudRate, QSerialPort::Directions directions)
{
if (directions != QSerialPort::AllDirections) {
setError(QSerialPortErrorInfo(QSerialPort::UnsupportedOperationError, QSerialPort::tr("Custom baud rate direction is unsupported")));
return false;
}
DCB dcb;
if (!getDcb(&dcb))
return false;
qt_set_baudrate(&dcb, baudRate);
return setDcb(&dcb);
}
bool QSerialPortPrivate::setDataBits(QSerialPort::DataBits dataBits)
{
DCB dcb;
if (!getDcb(&dcb))
return false;
qt_set_databits(&dcb, dataBits);
return setDcb(&dcb);
}
bool QSerialPortPrivate::setParity(QSerialPort::Parity parity)
{
DCB dcb;
if (!getDcb(&dcb))
return false;
qt_set_parity(&dcb, parity);
return setDcb(&dcb);
}
bool QSerialPortPrivate::setStopBits(QSerialPort::StopBits stopBits)
{
DCB dcb;
if (!getDcb(&dcb))
return false;
qt_set_stopbits(&dcb, stopBits);
return setDcb(&dcb);
}
bool QSerialPortPrivate::setFlowControl(QSerialPort::FlowControl flowControl)
{
DCB dcb;
if (!getDcb(&dcb))
return false;
qt_set_flowcontrol(&dcb, flowControl);
return setDcb(&dcb);
}
bool QSerialPortPrivate::completeAsyncCommunication(qint64 bytesTransferred)
{
communicationStarted = false;
if (bytesTransferred == qint64(-1))
return false;
return startAsyncRead();
}
bool QSerialPortPrivate::completeAsyncRead(qint64 bytesTransferred)
{
// Store the number of transferred bytes which are
// required only in waitForReadyRead() method.
readBytesTransferred = bytesTransferred;
if (bytesTransferred == qint64(-1)) {
readStarted = false;
return false;
}
if (bytesTransferred > 0)
buffer.append(readChunkBuffer.constData(), bytesTransferred);
readStarted = false;
bool result = true;
if (bytesTransferred == QSERIALPORT_BUFFERSIZE
|| queuedBytesCount(QSerialPort::Input) > 0) {
result = startAsyncRead();
} else {
result = startAsyncCommunication();
}
if (bytesTransferred > 0)
emitReadyRead();
return result;
}
bool QSerialPortPrivate::completeAsyncWrite(qint64 bytesTransferred)
{
Q_Q(QSerialPort);
// Store the number of transferred bytes which are
// required only in waitForBytesWritten() method.
writeBytesTransferred = bytesTransferred;
if (writeStarted) {
if (bytesTransferred == qint64(-1)) {
writeChunkBuffer.clear();
writeStarted = false;
return false;
}
Q_ASSERT(bytesTransferred == writeChunkBuffer.size());
writeChunkBuffer.clear();
emit q->bytesWritten(bytesTransferred);
writeStarted = false;
}
return _q_startAsyncWrite();
}
bool QSerialPortPrivate::startAsyncCommunication()
{
if (communicationStarted)
return true;
if (!communicationCompletionOverlapped)
communicationCompletionOverlapped = new Overlapped(this);
communicationCompletionOverlapped->clear();
communicationStarted = true;
if (!::qt_wait_comm_event_ex(handle,
&triggeredEventMask,
communicationCompletionOverlapped,
ioCompletionRoutine)) {
communicationStarted = false;
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::NoError) {
if (error.errorCode == QSerialPort::PermissionError)
error.errorCode = QSerialPort::ResourceError;
setError(error);
return false;
}
}
return true;
}
bool QSerialPortPrivate::startAsyncRead()
{
if (readStarted)
return true;
qint64 bytesToRead = QSERIALPORT_BUFFERSIZE;
if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - buffer.size())) {
bytesToRead = readBufferMaxSize - buffer.size();
if (bytesToRead <= 0) {
// Buffer is full. User must read data from the buffer
// before we can read more from the port.
return false;
}
}
Q_ASSERT(int(bytesToRead) <= readChunkBuffer.size());
if (!readCompletionOverlapped)
readCompletionOverlapped = new Overlapped(this);
readCompletionOverlapped->clear();
readStarted = true;
if (!::ReadFileEx(handle,
readChunkBuffer.data(),
bytesToRead,
readCompletionOverlapped,
ioCompletionRoutine)) {
readStarted = false;
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::NoError) {
if (error.errorCode == QSerialPort::PermissionError)
error.errorCode = QSerialPort::ResourceError;
if (error.errorCode != QSerialPort::ResourceError)
error.errorCode = QSerialPort::ReadError;
setError(error);
return false;
}
}
return true;
}
bool QSerialPortPrivate::_q_startAsyncWrite()
{
if (writeBuffer.isEmpty() || writeStarted)
return true;
writeChunkBuffer = writeBuffer.read();
if (!writeCompletionOverlapped)
writeCompletionOverlapped = new Overlapped(this);
writeCompletionOverlapped->clear();
writeStarted = true;
if (!::WriteFileEx(handle,
writeChunkBuffer.constData(),
writeChunkBuffer.size(),
writeCompletionOverlapped,
ioCompletionRoutine)) {
writeStarted = false;
QSerialPortErrorInfo error = getSystemError();
if (error.errorCode != QSerialPort::NoError) {
if (error.errorCode != QSerialPort::ResourceError)
error.errorCode = QSerialPort::WriteError;
setError(error);
return false;
}
}
return true;
}
void QSerialPortPrivate::handleNotification(DWORD bytesTransferred, DWORD errorCode,
OVERLAPPED *overlapped)
{
// This occurred e.g. after calling the CloseHandle() function,
// just skip handling at all.
if (handle == INVALID_HANDLE_VALUE)
return;
const QSerialPortErrorInfo error = getSystemError(errorCode);
if (error.errorCode != QSerialPort::NoError) {
setError(error);
return;
}
if (overlapped == communicationCompletionOverlapped)
completeAsyncCommunication(bytesTransferred);
else if (overlapped == readCompletionOverlapped)
completeAsyncRead(bytesTransferred);
else if (overlapped == writeCompletionOverlapped)
completeAsyncWrite(bytesTransferred);
else
Q_ASSERT(!"Unknown OVERLAPPED activated");
}
void QSerialPortPrivate::emitReadyRead()
{
Q_Q(QSerialPort);
emit q->readyRead();
}
qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
{
Q_Q(QSerialPort);
writeBuffer.append(data, maxSize);
if (!writeBuffer.isEmpty() && !writeStarted) {
if (!startAsyncWriteTimer) {
startAsyncWriteTimer = new QTimer(q);
QObjectPrivate::connect(startAsyncWriteTimer, &QTimer::timeout, this, &QSerialPortPrivate::_q_startAsyncWrite);
startAsyncWriteTimer->setSingleShot(true);
}
if (!startAsyncWriteTimer->isActive())
startAsyncWriteTimer->start();
}
return maxSize;
}
qint64 QSerialPortPrivate::queuedBytesCount(QSerialPort::Direction direction) const
{
COMSTAT comstat;
if (::ClearCommError(handle, nullptr, &comstat) == 0)
return -1;
return (direction == QSerialPort::Input)
? comstat.cbInQue
: ((direction == QSerialPort::Output) ? comstat.cbOutQue : -1);
}
inline bool QSerialPortPrivate::initialize(QIODevice::OpenMode mode)
{
DCB dcb;
if (!getDcb(&dcb))
return false;
restoredDcb = dcb;
qt_set_common_props(&dcb);
qt_set_baudrate(&dcb, inputBaudRate);
qt_set_databits(&dcb, dataBits);
qt_set_parity(&dcb, parity);
qt_set_stopbits(&dcb, stopBits);
qt_set_flowcontrol(&dcb, flowControl);
if (!setDcb(&dcb))
return false;
if (!::GetCommTimeouts(handle, &restoredCommTimeouts)) {
setError(getSystemError());
return false;
}
::ZeroMemory(&currentCommTimeouts, sizeof(currentCommTimeouts));
currentCommTimeouts.ReadIntervalTimeout = MAXDWORD;
if (!::SetCommTimeouts(handle, &currentCommTimeouts)) {
setError(getSystemError());
return false;
}
const DWORD eventMask = (mode & QIODevice::ReadOnly) ? EV_RXCHAR : 0;
if (!::SetCommMask(handle, eventMask)) {
setError(getSystemError());
return false;
}
if ((eventMask & EV_RXCHAR) && !startAsyncCommunication())
return false;
return true;
}
bool QSerialPortPrivate::setDcb(DCB *dcb)
{
if (!::SetCommState(handle, dcb)) {
setError(getSystemError());
return false;
}
return true;
}
bool QSerialPortPrivate::getDcb(DCB *dcb)
{
::ZeroMemory(dcb, sizeof(DCB));
dcb->DCBlength = sizeof(DCB);
if (!::GetCommState(handle, dcb)) {
setError(getSystemError());
return false;
}
return true;
}
QSerialPortErrorInfo QSerialPortPrivate::getSystemError(int systemErrorCode) const
{
if (systemErrorCode == -1)
systemErrorCode = ::GetLastError();
QSerialPortErrorInfo error;
error.errorString = qt_error_string(systemErrorCode);
switch (systemErrorCode) {
case ERROR_SUCCESS:
error.errorCode = QSerialPort::NoError;
break;
case ERROR_IO_PENDING:
error.errorCode = QSerialPort::NoError;
break;
case ERROR_MORE_DATA:
error.errorCode = QSerialPort::NoError;
break;
case ERROR_FILE_NOT_FOUND:
error.errorCode = QSerialPort::DeviceNotFoundError;
break;
case ERROR_PATH_NOT_FOUND:
error.errorCode = QSerialPort::DeviceNotFoundError;
break;
case ERROR_INVALID_NAME:
error.errorCode = QSerialPort::DeviceNotFoundError;
break;
case ERROR_ACCESS_DENIED:
error.errorCode = QSerialPort::PermissionError;
break;
case ERROR_INVALID_HANDLE:
error.errorCode = QSerialPort::ResourceError;
break;
case ERROR_INVALID_PARAMETER:
error.errorCode = QSerialPort::UnsupportedOperationError;
break;
case ERROR_BAD_COMMAND:
error.errorCode = QSerialPort::ResourceError;
break;
case ERROR_DEVICE_REMOVED:
error.errorCode = QSerialPort::ResourceError;
break;
case ERROR_OPERATION_ABORTED:
error.errorCode = QSerialPort::ResourceError;
break;
case WAIT_TIMEOUT:
error.errorCode = QSerialPort::TimeoutError;
break;
default:
error.errorCode = QSerialPort::UnknownError;
break;
}
return error;
}
// This table contains standard values of baud rates that
// are defined in file winbase.h
QList<qint32> QSerialPortPrivate::standardBaudRates()
{
static const QList<qint32> baudRates = {
CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400,
CBR_4800, CBR_9600, CBR_14400, CBR_19200, CBR_38400,
CBR_56000, CBR_57600, CBR_115200, CBR_128000, CBR_256000
};
return baudRates;
}
QSerialPort::Handle QSerialPort::handle() const
{
Q_D(const QSerialPort);
return d->handle;
}
void QSerialPortPrivate::ioCompletionRoutine(
DWORD errorCode, DWORD bytesTransfered,
OVERLAPPED *overlappedBase)
{
const auto overlapped = static_cast<Overlapped *>(overlappedBase);
if (overlapped->dptr) {
overlapped->dptr->handleNotification(bytesTransfered, errorCode,
overlappedBase);
} else {
delete overlapped;
}
}
QT_END_NAMESPACE