#include "lruserialport.h" #include #include static int lru_serial_port_id=1; //#define USE_QT_PORT #ifdef USE_QT_PORT class LruSerialPort::Implementation { public: QSerialPort realPort; Implemetation(LruSerialPort&) { } }; #else #include #include #include #define QGSERIALPORT_RX_BUFFER_SIZE 128 enum { RX_BUFFER_SIZE=QGSERIALPORT_RX_BUFFER_SIZE, RX_BUFFERS=32, RX_BUFFER_MASK=(RX_BUFFERS-1)}; static QEvent::Type rxEventType=QEvent::None; class ReceiverHander { public: virtual bool process_data(char* data, unsigned int len)=0; }; static QString getLastErrorMsg() { LPWSTR bufPtr = NULL; DWORD err = GetLastError(); FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, (LPWSTR)&bufPtr, 0, NULL); const QString result = (bufPtr) ? QString::fromUtf16((const ushort*)bufPtr).trimmed() : QString("Unknown Error %1").arg(err); LocalFree(bufPtr); return result; } static QString portFullPath(const QString& port) { return QString("\\\\.\\")+port; } class QgSerialPort: public QThread { public: struct { volatile HANDLE hCom; HANDLE hEvent; HANDLE hBreak; HANDLE hRead; HANDLE hWrite; HANDLE hEmpty; OVERLAPPED rx_overlap; OVERLAPPED tx_overlap; OVERLAPPED tx_empty_overlap; DWORD waitCommEvent; QObject* listener; ReceiverHander* receiverHandler; } cx; LruSerialPort& sp; QString portName; bool is_open; DWORD s_parity; DWORD s_baud; QgSerialPort(LruSerialPort& sport): sp(sport), is_open(false), s_parity(EVENPARITY), s_baud(CBR_9600) { memset(&cx, 0, sizeof cx); cx.hEvent=CreateEvent(0, FALSE, FALSE, 0); cx.hRead=CreateEvent(0, TRUE, FALSE, 0); cx.hWrite=CreateEvent(0, TRUE, TRUE, 0); cx.hBreak=CreateEvent(0, FALSE, FALSE, 0); cx.hEmpty=CreateEvent(0, TRUE, FALSE, 0); cx.rx_overlap.hEvent=cx.hRead; cx.tx_overlap.hEvent=cx.hWrite; if (rxEventType==QEvent::None) rxEventType=(QEvent::Type)QEvent::registerEventType(); cx.hCom=INVALID_HANDLE_VALUE; } void close() { please_terminate=true; CloseHandle(cx.hWrite); CloseHandle(cx.hRead); } ~QgSerialPort() { close(); } void setPortName(const QString name) { portName=name; } void setFlowControl(QSerialPort::FlowControl) { } void setDataBits(QSerialPort::DataBits) { } void setReadBufferSize(int/*n*/) { } void setParity(QSerialPort::Parity p) { s_parity= p==QSerialPort::EvenParity ? EVENPARITY : NOPARITY; } void setBaudRate(QSerialPort::BaudRate b) { s_baud= b==QSerialPort::Baud9600 ? CBR_9600: CBR_115200; } bool open(QIODevice::OpenMode) { QString name=portFullPath(portName); cx.hCom=CreateFileA(portName.toLatin1().constData(), GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (cx.hCom==INVALID_HANDLE_VALUE) { qDebug()<<"POER Error:"<=WAIT_ABANDONED_0 && ok<=WAIT_ABANDONED_0+1) break; } } if (cx.hCom==INVALID_HANDLE_VALUE && please_break) break; if (please_terminate) break; if (read_in) { DWORD errorWord=0; ClearCommError(cx.hCom, &errorWord, 0); errorWord&=~(CE_OVERRUN|CE_RXOVER); if (errorWord) { tempWaitCommEvent=0; continue; } if (cx.receiverHandler) { if (!cx.receiverHandler->process_data(buffer[current_buffer], read_in)) { tempWaitCommEvent=0; continue; } } rx_consumed[current_buffer]=1; Q_EMIT sp.asynchReadyRead(current_buffer, buffer[current_buffer], read_in, tempWaitCommEvent); //sp.propagateData(current_buffer, buffer[current_buffer], read_in, tempWaitCommEvent); unsigned int next_buffer=(current_buffer+1) & RX_BUFFER_MASK; if (rx_consumed[next_buffer]==0) current_buffer=next_buffer; } tempWaitCommEvent=0; } } } QByteArray pendingData; void flush() { } int bytesAvailable() const { return pendingData.size(); } QByteArray readAll() { QByteArray tmp=pendingData; pendingData.clear(); return tmp; } qint64 write(const QByteArray& d) { write_(d.constData(), d.size()); return d.size(); } qint64 write(const char* d, int len) { write_(d, len); return len; } }; class LruSerialPort::Implementation { public: QgSerialPort realPort; Implementation(LruSerialPort& lru): realPort(lru) { } }; #endif LruSerialPort::LruSerialPort(const QString & name, deviceID device, QSerialPort::BaudRate baud, QSerialPort::Parity parity): //QSerialPort(), port_name(name), portId(lru_serial_port_id), realPortOk(false), inFilter(0), enabled(true), chars_in(0), chars_out(0), p_(* new Implementation(*this)) { if (!name.isEmpty() && (!name.startsWith('<'))) { p_.realPort.setPortName(name); p_.realPort.setFlowControl(QSerialPort::NoFlowControl); p_.realPort.setDataBits(QSerialPort::Data8); p_.realPort.setReadBufferSize(256); p_.realPort.setParity(parity); p_.realPort.setBaudRate(baud); p_.realPort.open(QIODevice::ReadWrite); realPortOk=p_.realPort.isOpen(); qDebug()<<"Open"<serialFilterIn(*this, data); if (ok) return data; } return QByteArray(); } qint64 LruSerialPort::write(const QByteArray& data) { chars_out+=data.size(); if (enabled && realPortOk) return p_.realPort.write(data); else return 0; } void LruSerialPort::writeChar(char c) { ++chars_out; if (enabled && realPortOk) p_.realPort.write(&c, 1); } void LruSerialPort::flush() { if (realPortOk) p_.realPort.flush(); }