void QSerialPortPrivate::close() { Q_Q(QSerialPort); if (!::CancelIo(handle)) q->setError(decodeSystemError()); readCompletionNotifier->setEnabled(false); writeCompletionNotifier->setEnabled(false); communicationNotifier->setEnabled(false); readBuffer.clear(); writeStarted = false; writeBuffer.clear(); readyReadEmitted = false; parityErrorOccurred = false; if (settingsRestoredOnClose) { if (!::SetCommState(handle, &restoredDcb)) q->setError(decodeSystemError()); else if (!::SetCommTimeouts(handle, &restoredCommTimeouts)) q->setError(decodeSystemError()); } if (!::CloseHandle(handle)) q->setError(decodeSystemError()); handle = INVALID_HANDLE_VALUE; }
bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { Q_Q(QSerialPort); // FIXME: Maybe need added check an ReadWrite open mode? Q_UNUSED(mode) if (!loadDevices()) { q->setError(QSerialPort::UnknownError); return false; } RCommServ server; errnum = server.Connect(); if (errnum != KErrNone) { q->setError(decodeSystemError()); return false; } if (systemLocation.contains("BTCOMM")) errnum = server.LoadCommModule(KBluetoothModuleName); else if (systemLocation.contains("IRCOMM")) errnum = server.LoadCommModule(KInfraRedModuleName); else if (systemLocation.contains("ACM")) errnum = server.LoadCommModule(KACMModuleName); else errnum = server.LoadCommModule(KRS232ModuleName); if (errnum != KErrNone) { q->setError(decodeSystemError()); return false; } // In Symbian OS port opening only in R/W mode? TPtrC portName(static_cast<const TUint16*>(systemLocation.utf16()), systemLocation.length()); errnum = descriptor.Open(server, portName, ECommExclusive); if (errnum != KErrNone) { q->setError(decodeSystemError()); return false; } // Save current port settings. errnum = descriptor.Config(restoredSettings); if (errnum != KErrNone) { q->setError(decodeSystemError()); return false; } detectDefaultSettings(); return true; }
bool QSerialPortPrivate::startAsyncCommunication() { Q_Q(QSerialPort); initializeOverlappedStructure(communicationOverlapped); if (!::WaitCommEvent(handle, &triggeredEventMask, &communicationOverlapped)) { const QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { q->setError(decodeSystemError()); return false; } } return true; }
bool QSerialPortPrivate::waitForBytesWritten(int msecs) { Q_Q(QSerialPort); if (writeBuffer.isEmpty()) return false; QElapsedTimer stopWatch; stopWatch.start(); forever { bool timedOut = false; HANDLE triggeredEvent = 0; if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &triggeredEvent) || !triggeredEvent) { if (!timedOut) q->setError(decodeSystemError()); return false; } if (triggeredEvent == communicationOverlapped.hEvent) { _q_completeAsyncRead(); } else if (triggeredEvent == readCompletionOverlapped.hEvent) { _q_completeAsyncRead(); } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { _q_completeAsyncWrite(); return error == QSerialPort::NoError; } else { return false; } } return false; }
bool QSerialPortPrivate::writeDataOneShot() { Q_Q(QSerialPort); pendingBytesWritten = -1; while (!writeBuffer.isEmpty()) { pendingBytesWritten = writeToPort(writeBuffer.readPointer(), writeBuffer.nextDataBlockSize()); if (pendingBytesWritten <= 0) { QSerialPort::SerialPortError errorL = decodeSystemError(); if (errorL != QSerialPort::ResourceError) errorL = QSerialPort::WriteError; q->setError(errorL); return false; } writeBuffer.free(pendingBytesWritten); emit q->bytesWritten(pendingBytesWritten); } return (pendingBytesWritten < 0)? false: true; }
void QSerialPortPrivate::processIoErrors(bool error) { Q_Q(QSerialPort); if (error) { q->setError(QSerialPort::ResourceError); return; } DWORD errors = 0; if (!::ClearCommError(handle, &errors, NULL)) { q->setError(decodeSystemError()); return; } if (errors & CE_FRAME) { q->setError(QSerialPort::FramingError); } else if (errors & CE_RXPARITY) { q->setError(QSerialPort::ParityError); parityErrorOccurred = true; } else if (errors & CE_BREAK) { q->setError(QSerialPort::BreakConditionError); } else { q->setError(QSerialPort::UnknownError); } }
bool QSerialPortPrivate::startAsyncRead() { Q_Q(QSerialPort); DWORD bytesToRead = policy == QSerialPort::IgnorePolicy ? ReadChunkSize : 1; if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { bytesToRead = readBufferMaxSize - readBuffer.size(); if (bytesToRead == 0) { // Buffer is full. User must read data from the buffer // before we can read more from the port. return false; } } initializeOverlappedStructure(readCompletionOverlapped); if (::ReadFile(handle, readChunkBuffer.data(), bytesToRead, NULL, &readCompletionOverlapped)) return true; QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { if (error != QSerialPort::ResourceError) error = QSerialPort::ReadError; q->setError(error); return false; } return true; }
bool QSerialPortPrivate::updateCommTimeouts() { Q_Q(QSerialPort); if (!::SetCommTimeouts(handle, ¤tCommTimeouts)) { q->setError(decodeSystemError()); return false; } return true; }
bool QSerialPortPrivate::updateDcb() { Q_Q(QSerialPort); if (!::SetCommState(handle, ¤tDcb)) { q->setError(decodeSystemError()); return false; } return true; }
bool QSerialPortPrivate::setBreakEnabled(bool set) { Q_Q(QSerialPort); if (set ? !::SetCommBreak(handle) : !::ClearCommBreak(handle)) { q->setError(decodeSystemError()); return false; } return true; }
bool QSerialPortPrivate::setRequestToSend(bool set) { Q_Q(QSerialPort); if (!::EscapeCommFunction(handle, set ? SETRTS : CLRRTS)) { q->setError(decodeSystemError()); return false; } return true; }
bool QSerialPortPrivate::setDataTerminalReady(bool set) { Q_Q(QSerialPort); if (!::EscapeCommFunction(handle, set ? SETDTR : CLRDTR)) { q->setError(decodeSystemError()); return false; } currentDcb.fDtrControl = set ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE; return true; }
QSerialPortPrivate::QSerialPortPrivate(QSerialPort *q) : QSerialPortPrivateData(q) , handle(INVALID_HANDLE_VALUE) , parityErrorOccurred(false) , readChunkBuffer(ReadChunkSize, 0) , readyReadEmitted(0) , writeStarted(false) , communicationNotifier(new QWinEventNotifier(q)) , readCompletionNotifier(new QWinEventNotifier(q)) , writeCompletionNotifier(new QWinEventNotifier(q)) , originalEventMask(0) , triggeredEventMask(0) { ::ZeroMemory(&communicationOverlapped, sizeof(communicationOverlapped)); communicationOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); if (!communicationOverlapped.hEvent) q->setError(decodeSystemError()); else { communicationNotifier->setHandle(communicationOverlapped.hEvent); q->connect(communicationNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_completeAsyncCommunication())); } ::ZeroMemory(&readCompletionOverlapped, sizeof(readCompletionOverlapped)); readCompletionOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); if (!readCompletionOverlapped.hEvent) q->setError(decodeSystemError()); else { readCompletionNotifier->setHandle(readCompletionOverlapped.hEvent); q->connect(readCompletionNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_completeAsyncRead())); } ::ZeroMemory(&writeCompletionOverlapped, sizeof(writeCompletionOverlapped)); writeCompletionOverlapped.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); if (!writeCompletionOverlapped.hEvent) q->setError(decodeSystemError()); else { writeCompletionNotifier->setHandle(writeCompletionOverlapped.hEvent); q->connect(writeCompletionNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_completeAsyncWrite())); } }
QSerialPort::PinoutSignals QSerialPortPrivate::pinoutSignals() { Q_Q(QSerialPort); DWORD modemStat = 0; if (!::GetCommModemStatus(handle, &modemStat)) { q->setError(decodeSystemError()); 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, NULL, 0, &modemStat, sizeof(modemStat), &bytesReturned, NULL)) { q->setError(decodeSystemError()); return ret; } if (modemStat & SERIAL_DTR_STATE) ret |= QSerialPort::DataTerminalReadySignal; if (modemStat & SERIAL_RTS_STATE) ret |= QSerialPort::RequestToSendSignal; return ret; }
bool QSerialPortPrivate::flush() { Q_Q(QSerialPort); bool returnValue = true; if (!startAsyncWrite()) returnValue = false; if (!::FlushFileBuffers(handle)) { q->setError(decodeSystemError()); returnValue = false; } return returnValue; }
void QSerialPortPrivate::_q_completeAsyncCommunication() { Q_Q(QSerialPort); DWORD numberOfBytesTransferred = 0; if (!::GetOverlappedResult(handle, &communicationOverlapped, &numberOfBytesTransferred, FALSE)) q->setError(decodeSystemError()); bool error = false; // Check for unexpected event. This event triggered when pulled previously // opened device from the system, when opened as for not to read and not to // write options and so forth. if (triggeredEventMask == 0) error = true; // Workaround for standard CDC ACM serial ports, for which triggered an // unexpected event EV_TXEMPTY at data transmission. if ((originalEventMask & triggeredEventMask) == 0) { if ((triggeredEventMask & EV_TXEMPTY) == 0) error = true; } // Start processing a caught error. if (error || (EV_ERR & triggeredEventMask)) processIoErrors(error); if (triggeredEventMask & (EV_CTS | EV_DSR | EV_RLSD | EV_RING) ) { QSerialPort::PinoutSignals signals_mask = 0; if (triggeredEventMask & EV_CTS) signals_mask |= QSerialPort::ClearToSendSignal; if (triggeredEventMask & EV_DSR) signals_mask |= QSerialPort::DataSetReadySignal; //No definition in PinoutSignals if (triggeredEventMask & EV_RLSD) signals_mask |= QSerialPort::ReceivedDataSignal; if (triggeredEventMask & EV_RING) signals_mask |= QSerialPort::RingIndicatorSignal; emit q->pinoutSignalsChanged(signals_mask); } if (!error && (triggeredEventMask & EV_RXCHAR) ) startAsyncRead(); else startAsyncCommunication(); }
void QSerialPortPrivate::_q_completeAsyncWrite() { Q_Q(QSerialPort); DWORD numberOfBytesTransferred = 0; if (!::GetOverlappedResult(handle, &writeCompletionOverlapped, &numberOfBytesTransferred, FALSE)) { numberOfBytesTransferred = 0; q->setError(decodeSystemError()); } if (numberOfBytesTransferred > 0) { writeBuffer.free(numberOfBytesTransferred); emit q->bytesWritten(numberOfBytesTransferred); } writeStarted = false; startAsyncWrite(); }
bool QSerialPortPrivate::clear(QSerialPort::Directions directions) { Q_Q(QSerialPort); DWORD flags = 0; if (directions & QSerialPort::Input) flags |= PURGE_RXABORT | PURGE_RXCLEAR; if (directions & QSerialPort::Output) { flags |= PURGE_TXABORT | PURGE_TXCLEAR; writeStarted = false; } if (!::PurgeComm(handle, flags)) { q->setError(decodeSystemError()); return false; } return true; }
bool QSerialPortPrivate::waitForReadyRead(int msecs) { Q_Q(QSerialPort); QElapsedTimer stopWatch; stopWatch.start(); const qint64 initialReadBufferSize = readBuffer.size(); qint64 currentReadBufferSize = initialReadBufferSize; do { bool timedOut = false; HANDLE triggeredEvent = 0; if (!waitAnyEvent(timeoutValue(msecs, stopWatch.elapsed()), &timedOut, &triggeredEvent) || !triggeredEvent) { // This is occur timeout or another error if (!timedOut) q->setError(decodeSystemError()); return false; } if (triggeredEvent == communicationOverlapped.hEvent) { _q_completeAsyncCommunication(); } else if (triggeredEvent == readCompletionOverlapped.hEvent) { _q_completeAsyncRead(); if (qint64(readBuffer.size()) != currentReadBufferSize) currentReadBufferSize = readBuffer.size(); else if (initialReadBufferSize != currentReadBufferSize) return true; } else if (triggeredEvent == writeCompletionOverlapped.hEvent) { _q_completeAsyncWrite(); } else { return false; } } while (msecs == -1 || timeoutValue(msecs, stopWatch.elapsed()) > 0); return false; }
void QSerialPortPrivate::_q_completeAsyncRead() { Q_Q(QSerialPort); DWORD numberOfBytesTransferred = 0; if (!::GetOverlappedResult(handle, &readCompletionOverlapped, &numberOfBytesTransferred, FALSE)) q->setError(decodeSystemError()); if (numberOfBytesTransferred > 0) { readBuffer.append(readChunkBuffer.left(numberOfBytesTransferred)); if (!emulateErrorPolicy()) emitReadyRead(); } // start async read for possible remainder into driver queue if ((numberOfBytesTransferred > 0) && (policy == QSerialPort::IgnorePolicy)) startAsyncRead(); else // driver queue is emplty, so startup wait comm event startAsyncCommunication(); }
bool QSerialPortPrivate::startAsyncWrite() { Q_Q(QSerialPort); if (writeBuffer.isEmpty() || writeStarted) return true; initializeOverlappedStructure(writeCompletionOverlapped); if (!::WriteFile(handle, writeBuffer.readPointer(), writeBuffer.nextDataBlockSize(), NULL, &writeCompletionOverlapped)) { QSerialPort::SerialPortError error = decodeSystemError(); if (error != QSerialPort::NoError) { if (error != QSerialPort::ResourceError) error = QSerialPort::WriteError; q->setError(error); return false; } } writeStarted = true; return true; }
bool QSerialPortPrivate::open(QIODevice::OpenMode mode) { Q_Q(QSerialPort); DWORD desiredAccess = 0; originalEventMask = EV_ERR | EV_CTS | EV_DSR | EV_RING /*| EV_RLSD*/; if (mode & QIODevice::ReadOnly) { desiredAccess |= GENERIC_READ; originalEventMask |= EV_RXCHAR; } if (mode & QIODevice::WriteOnly) desiredAccess |= GENERIC_WRITE; handle = ::CreateFile(reinterpret_cast<const wchar_t*>(systemLocation.utf16()), desiredAccess, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (handle == INVALID_HANDLE_VALUE) { q->setError(decodeSystemError()); return false; } ::ZeroMemory(&restoredDcb, sizeof(restoredDcb)); restoredDcb.DCBlength = sizeof(restoredDcb); if (!::GetCommState(handle, &restoredDcb)) { q->setError(decodeSystemError()); return false; } currentDcb = restoredDcb; currentDcb.fBinary = TRUE; currentDcb.fInX = FALSE; currentDcb.fOutX = FALSE; currentDcb.fAbortOnError = FALSE; currentDcb.fNull = FALSE; currentDcb.fErrorChar = FALSE; if (currentDcb.fDtrControl == DTR_CONTROL_HANDSHAKE) currentDcb.fDtrControl = DTR_CONTROL_DISABLE; if (!updateDcb()) return false; if (!::GetCommTimeouts(handle, &restoredCommTimeouts)) { q->setError(decodeSystemError()); return false; } ::ZeroMemory(¤tCommTimeouts, sizeof(currentCommTimeouts)); currentCommTimeouts.ReadIntervalTimeout = MAXDWORD; if (!updateCommTimeouts()) return false; if (mode & QIODevice::ReadOnly) readCompletionNotifier->setEnabled(true); if (mode & QIODevice::WriteOnly) writeCompletionNotifier->setEnabled(true); if (!::SetCommMask(handle, originalEventMask)) { q->setError(decodeSystemError()); return false; } if (!startAsyncCommunication()) return false; communicationNotifier->setEnabled(true); return true; }