void ModbusRtu::processPacket()
{
	QMutexLocker lock(&mMutex);
	quint8 cs = mCurrentSlave;
	if (mCrc != mCrcBuilder.getValue()) {
		resetStateEngine();
		processPending();
		mMutex.unlockInline();
		emit errorReceived(CrcError, cs, 0);
		return;
	}
	if ((mFunction & 0x80) != 0) {
		quint8 errorCode = static_cast<quint8>(mData[0]);
		resetStateEngine();
		processPending();
		mMutex.unlockInline();
		emit errorReceived(Exception, cs, errorCode);
		return;
	}
	if (mState == Function) {
		FunctionCode function = mFunction;
		resetStateEngine();
		processPending();
		mMutex.unlockInline();
		emit errorReceived(Unsupported, cs, function);
		return;
	}
	FunctionCode function = mFunction;
	switch (function) {
	case ReadHoldingRegisters:
	case ReadInputRegisters:
	{
		QList<quint16> registers;
		for (int i=0; i<mData.length(); i+=2) {
			registers.append(toUInt16(mData, i));
		}
		resetStateEngine();
		processPending();
		mMutex.unlockInline();
		emit readCompleted(function, cs, registers);
		return;
	}
	case WriteSingleRegister:
	{
		quint16 value = toUInt16(mData, 0);
		quint16 startAddress = mStartAddress;
		resetStateEngine();
		processPending();
		mMutex.unlockInline();
		emit writeCompleted(function, cs, startAddress, value);
		return;
	}
	default:
		break;
	}
}
bool VirtualSerialDevice::open(OpenMode mode)
{
    Q_ASSERT(QThread::currentThread() == thread());
    if (isOpen()) return true;

    d->portHandle = CreateFileA(windowsPortName(portName).toAscii(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (d->portHandle == INVALID_HANDLE_VALUE) {
        setErrorString(tr("The port %1 could not be opened: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        return false;
    }

    DCB commState;
    memset(&commState, 0, sizeof(DCB));
    commState.DCBlength = sizeof(DCB);
    bool ok = GetCommState(d->portHandle, &commState);
    if (ok) {
        commState.BaudRate = CBR_115200;
        commState.fBinary = TRUE;
        commState.fParity = FALSE;
        commState.fOutxCtsFlow = FALSE;
        commState.fOutxDsrFlow = FALSE;
        commState.fInX = FALSE;
        commState.fOutX = FALSE;
        commState.fNull = FALSE;
        commState.fAbortOnError = FALSE;
        commState.fDsrSensitivity = FALSE;
        commState.fDtrControl = DTR_CONTROL_DISABLE;
        commState.ByteSize = 8;
        commState.Parity = NOPARITY;
        commState.StopBits = ONESTOPBIT;
        ok = SetCommState(d->portHandle, &commState);
    }
    if (!ok) {
        qWarning("%s setting comm state", qPrintable(winErrorMessage(GetLastError())));
    }

    // http://msdn.microsoft.com/en-us/library/aa363190(v=vs.85).aspx says this means
    // "the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received"
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout = MAXDWORD;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;
    SetCommTimeouts(d->portHandle, &timeouts);

    d->writeOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->writeCompleteNotifier = new QWinEventNotifier(d->writeOverlapped.hEvent, this);
    connect(d->writeCompleteNotifier, SIGNAL(activated(HANDLE)), this, SLOT(writeCompleted()));

    // This is how we implement readyRead notifications
    d->commEventOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    d->commEventNotifier = new QWinEventNotifier(d->commEventOverlapped.hEvent, this);
    connect(d->commEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(commEventOccurred()));

    if (!SetCommMask(d->portHandle, EV_RXCHAR)) {
        // What to do?
        qWarning("%s: Could not set comm mask, err=%d", Q_FUNC_INFO, (int)GetLastError());
    }
    bool result = WaitCommEvent(d->portHandle, &d->commEventMask, &d->commEventOverlapped);
    Q_ASSERT(result == false); // Can't see how it would make sense to be anything else...
    (void)result; // For release build
    if (GetLastError() != ERROR_IO_PENDING) {
        setErrorString(tr("An error occurred while waiting for read notifications from %1: %2").
                       arg(portName, winErrorMessage(GetLastError())));
        close();
        return false;
    }

    ok = QIODevice::open(mode);
    if (!ok) close();
    return ok;
}