bool StandardSerialPortBackend::writeDataFrame(const QByteArray &data) { // qDebug() << "!d" << tr("DBG -- Serial Port writeDataFrame..."); QByteArray copy(data); copy.resize(copy.size() + 1); copy[copy.size() - 1] = sioChecksum(copy, copy.size() - 1); SioWorker::usleep(50); return writeRawFrame(copy); }
QByteArray StandardSerialPortBackend::readDataFrame(uint size, bool verbose) { // qDebug() << "!d" << tr("DBG -- Serial Port readDataFrame..."); QByteArray data = readRawFrame(size + 1, verbose); if (data.isEmpty()) { return data; } quint8 expected = (quint8)data.at(size); quint8 got = sioChecksum(data, size); if (expected == got) { data.resize(size); return data; } else { if (verbose) { qWarning() << "!w" << tr("Data frame checksum error, expected: %1, got: %2. (%3)") .arg(expected) .arg(got) .arg(QString(data.toHex())); } data.clear(); return data; } }
QByteArray StandardSerialPortBackend::readCommandFrame() { // qDebug() << "!d" << tr("DBG -- Serial Port readCommandFrame..."); QByteArray data; if(mMethod==HANDSHAKE_SOFTWARE) { if (!PurgeComm(mHandle, PURGE_RXCLEAR)) { qCritical() << "!e" << tr("Cannot clear serial port read buffer: %1").arg(lastErrorMessage()); return data; } const int size = 4; quint8 expected = 0; quint8 got = 1; do { DWORD result; char c; if(ReadFile(mHandle, &c, 1, &result, NULL) && result == 1) { data.append(c); if(data.size()==size+2) { data.remove(0,1); } if(data.size()==size+1) { for(int i=0 ; i<mSioDevices.size() ; i++) { if(data.at(0)==mSioDevices[i]) { expected = (quint8)data.at(size); got = sioChecksum(data, size); break; } } } } } while(got!=expected && !mCanceled); if(got==expected) { data.resize(size); // After sending the last byte of the command frame // ATARI does not drop the command line immediately. // Within this small time window ATARI is not able to process the ACK byte. // For the "software handshake" approach, we need to wait here a little bit. QThread::usleep(500); } else { data.clear(); } } else { DWORD MASK; DWORD MODEM_STAT; DWORD tmp; switch (mMethod) { case HANDSHAKE_RI: MASK = EV_RING; MODEM_STAT = MS_RING_ON; break; case HANDSHAKE_DSR: MASK = EV_DSR; MODEM_STAT = MS_DSR_ON; break; case HANDSHAKE_CTS: MASK = EV_CTS; MODEM_STAT = MS_CTS_ON; break; case HANDSHAKE_NO_HANDSHAKE: default: MASK = EV_RXCHAR; MODEM_STAT = 0; break; } if (!SetCommMask(mHandle, MASK)) { qCritical() << "!e" << tr("Cannot set serial port event mask: %1").arg(lastErrorMessage()); return data; } int retries = 0, totalRetries = 0; do { data.clear(); OVERLAPPED ov; memset(&ov, 0, sizeof(ov)); ov.hEvent = CreateEvent(0, true, false, 0); HANDLE events[2]; events[0] = ov.hEvent; events[1] = mCancelHandle; if (!WaitCommEvent(mHandle, &tmp, &ov)) { if (GetLastError() == ERROR_IO_PENDING) { DWORD x = WaitForMultipleObjects(2, events, false, INFINITE); CloseHandle(ov.hEvent); if (x == WAIT_OBJECT_0 + 1) { data.clear(); return data; } if (x == WAIT_FAILED) { qCritical() << "!e" << tr("Cannot wait for serial port event: %1").arg(lastErrorMessage()); data.clear(); return data; } } else { CloseHandle(ov.hEvent); qCritical() << "!e" << tr("Cannot wait for serial port event: %1").arg(lastErrorMessage()); return data; } } // for hardware handshake methods check if the command line status is ON if( (MODEM_STAT != 0) && (!GetCommModemStatus(mHandle, &tmp) || !(tmp & MODEM_STAT)) )continue; if(MASK != EV_RXCHAR) { if (!PurgeComm(mHandle, PURGE_RXCLEAR)) { qCritical() << "!e" << tr("Cannot clear serial port read buffer: %1").arg(lastErrorMessage()); return data; } } // qDebug() << "!d" << tr("DBG -- Serial Port, just about to readDataFrame..."); data = readDataFrame(4, false); if (!data.isEmpty()) { // qDebug() << "!d" << tr("DBG -- Serial Port, data not empty: [%1]").arg(data.data()); if(MASK != EV_RXCHAR) { // do { GetCommModemStatus(mHandle, &tmp); } while ((tmp & MODEM_STAT) && !mCanceled); } else { // After sending the last byte of the command frame // ATARI does not drop the command line immediately. // Within this small time window ATARI is not able to process the ACK byte. // For the "software handshake" approach, we need to wait here a little bit. QThread::usleep(500); } break; } else { retries++; totalRetries++; if (retries == 2) { retries = 0; if (mHighSpeed) { setNormalSpeed(); } else { setHighSpeed(); } } } // } while (totalRetries < 100); } while (1); } return data; }