From a955ae9ea8b4eb08c42fb8f64fb1233a221bbcf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Martel?= Date: Fri, 14 Aug 2015 07:50:51 -0400 Subject: [PATCH] Dev... --- MasterCtrl.pro | 19 +- Sources/232NetworkCommIF.cpp | 16 +- Sources/232NetworkCommIF.h | 16 +- Sources/AbstractNetworkInterface.h | 10 + Sources/DeadboltDevice.cpp | 16 + Sources/DeadboltDevice.h | 20 + Sources/MasterCtrl.cpp | 5 + Sources/MasterCtrl.h | 3 + Sources/NetworkProtocol.cpp | 83 +- Sources/NetworkProtocol.h | 8 +- Sources/main.cpp | 2 +- Sources/qextserialport/qextserialport.cpp | 254 +++++ Sources/qextserialport/qextserialport.h | 333 +++++++ .../qextserialport/qextserialport_global.h | 18 + Sources/qextserialport/qwineventnotifier_p.h | 94 ++ Sources/qextserialport/win_qextserialport.cpp | 868 ++++++++++++++++++ 16 files changed, 1730 insertions(+), 35 deletions(-) create mode 100644 Sources/AbstractNetworkInterface.h create mode 100644 Sources/DeadboltDevice.cpp create mode 100644 Sources/DeadboltDevice.h create mode 100644 Sources/qextserialport/qextserialport.cpp create mode 100644 Sources/qextserialport/qextserialport.h create mode 100644 Sources/qextserialport/qextserialport_global.h create mode 100644 Sources/qextserialport/qwineventnotifier_p.h create mode 100644 Sources/qextserialport/win_qextserialport.cpp diff --git a/MasterCtrl.pro b/MasterCtrl.pro index 4715243..287393f 100644 --- a/MasterCtrl.pro +++ b/MasterCtrl.pro @@ -1,5 +1,5 @@ -QT += Network - +#QT += Network +QT += gui declarative network HEADERS += \ Sources/MasterCtrl.h \ @@ -7,7 +7,9 @@ HEADERS += \ Sources/485NetworkCommIF.h \ Sources/EthernetNetworkCommIF.h \ Sources/232NetworkCommIF.h \ - Sources/NetworkProtocol.h + Sources/NetworkProtocol.h \ + Sources/AbstractNetworkInterface.h \ + Sources/DeadboltDevice.h \ SOURCES += \ Sources/main.cpp \ @@ -15,7 +17,14 @@ SOURCES += \ Sources/485NetworkCommIF.cpp \ Sources/232NetworkCommIF.cpp \ Sources/EthernetNetworkCommIF.cpp \ - Sources/NetworkProtocol.cpp + Sources/NetworkProtocol.cpp \ + Sources/DeadboltDevice.cpp + + +#win32:SOURCES += $$PWD/Source/qextserialport/win_qextserialport.cpp \ +# $$PWD/Source/qextserialport/qextserialenumerator_win.cpp +#win32:DEFINES += _TTY_WIN_ WINVER=0x0501 INCLUDEPATH += $$PWD/ \ - $$PWD/Sources/ + $$PWD/Sources/ \ + $$PWD/Sources/qextserialport/ diff --git a/Sources/232NetworkCommIF.cpp b/Sources/232NetworkCommIF.cpp index 3947705..f7384e3 100644 --- a/Sources/232NetworkCommIF.cpp +++ b/Sources/232NetworkCommIF.cpp @@ -1,5 +1,19 @@ #include "232NetworkCommIF.h" -C232NetworkCommIF::C232NetworkCommIF() +C232NetworkCommIF::C232NetworkCommIF(CAbstractNetworkCommIF *DeviceHandle) { + mDeviceHandle = DeviceHandle; + mNetworkProtocol = new CNetworkProtocol(this); +} +C232NetworkCommIF::~C232NetworkCommIF() +{ + delete mNetworkProtocol; +} + +int C232NetworkCommIF::NewFrameReceived(QByteArray Frame) +{ + //FWD to device... + //Nothing to do with the data here, up it goes to the device! + mDeviceHandle->NewFrameReceived(Frame); + return 1; } diff --git a/Sources/232NetworkCommIF.h b/Sources/232NetworkCommIF.h index 43e2ab3..f8b9d7f 100644 --- a/Sources/232NetworkCommIF.h +++ b/Sources/232NetworkCommIF.h @@ -1,10 +1,22 @@ #ifndef _232NETWORKCOMMIF_H #define _232NETWORKCOMMIF_H -class C232NetworkCommIF +#include "GlobalDefine.h" +#include "AbstractNetworkInterface.h" +#include "NetworkProtocol.h" + +class C232NetworkCommIF : public CAbstractNetworkCommIF { public: - C232NetworkCommIF(); + C232NetworkCommIF(CAbstractNetworkCommIF *DeviceHandle); + ~C232NetworkCommIF(); + + + virtual int NewFrameReceived(QByteArray Frame); + +private: + CNetworkProtocol *mNetworkProtocol; + CAbstractNetworkCommIF *mDeviceHandle; }; #endif // _232NETWORKCOMMIF_H diff --git a/Sources/AbstractNetworkInterface.h b/Sources/AbstractNetworkInterface.h new file mode 100644 index 0000000..75ee027 --- /dev/null +++ b/Sources/AbstractNetworkInterface.h @@ -0,0 +1,10 @@ +#ifndef ABSTRACTNETWORKINTERFACE_H +#define ABSTRACTNETWORKINTERFACE_H +#include + +class CAbstractNetworkCommIF +{ +public: + virtual int NewFrameReceived(QByteArray Frame) = 0; +}; +#endif // ABSTRACTNETWORKINTERFACE_H diff --git a/Sources/DeadboltDevice.cpp b/Sources/DeadboltDevice.cpp new file mode 100644 index 0000000..7422146 --- /dev/null +++ b/Sources/DeadboltDevice.cpp @@ -0,0 +1,16 @@ +#include "DeadboltDevice.h" + +CDeadboltDevice::CDeadboltDevice() +{ + mNetworkCommInterface = new C232NetworkCommIF(this); +} + +CDeadboltDevice::~CDeadboltDevice() +{ + delete mNetworkCommInterface; +} + +int CDeadboltDevice::NewFrameReceived(QByteArray Frame) +{ + return 0; +} diff --git a/Sources/DeadboltDevice.h b/Sources/DeadboltDevice.h new file mode 100644 index 0000000..d0ea1e4 --- /dev/null +++ b/Sources/DeadboltDevice.h @@ -0,0 +1,20 @@ +#ifndef DEADBOLTDEVICE_H +#define DEADBOLTDEVICE_H + +#include "GlobalDefine.h" +#include "232NetworkCommIF.h" +//#include "AbstractNetworkInterface.h" + + +class CDeadboltDevice: public CAbstractNetworkCommIF +{ +public: + CDeadboltDevice(); + ~CDeadboltDevice(); + virtual int NewFrameReceived(QByteArray Frame); + + + C232NetworkCommIF *mNetworkCommInterface; +}; + +#endif // DEADBOLTDEVICE_H diff --git a/Sources/MasterCtrl.cpp b/Sources/MasterCtrl.cpp index cd3699b..0ec8c84 100644 --- a/Sources/MasterCtrl.cpp +++ b/Sources/MasterCtrl.cpp @@ -3,8 +3,13 @@ CMasterCtrl::CMasterCtrl() { qDebug("Creation..."); + mDeadBoltDevice = new CDeadboltDevice; } +CMasterCtrl::~CMasterCtrl() +{ + delete mDeadBoltDevice; +} void CMasterCtrl::Start() { qDebug("Started!"); diff --git a/Sources/MasterCtrl.h b/Sources/MasterCtrl.h index b546534..dc764c1 100644 --- a/Sources/MasterCtrl.h +++ b/Sources/MasterCtrl.h @@ -2,13 +2,16 @@ #define MASTERCTRL_H #include "GlobalDefine.h" +#include "DeadboltDevice.h" class CMasterCtrl { public: CMasterCtrl(); + ~CMasterCtrl(); void Start(void); + CDeadboltDevice *mDeadBoltDevice; }; #endif // MASTERCTRL_H diff --git a/Sources/NetworkProtocol.cpp b/Sources/NetworkProtocol.cpp index 8e8a21f..543b960 100644 --- a/Sources/NetworkProtocol.cpp +++ b/Sources/NetworkProtocol.cpp @@ -1,11 +1,12 @@ #include "NetworkProtocol.h" +#include "QByteArray" - -CNetworkProtocol::CNetworkProtocol() +CNetworkProtocol::CNetworkProtocol(CAbstractNetworkCommIF *Parent) { + mParentHandle = Parent; ResetRxStateMachine(); } @@ -32,42 +33,75 @@ unsigned char CNetworkProtocol::CalcCRC(char *Buffer, int Size) return CRC; } - -int CNetworkProtocol::TxData(unsigned char MessageID,unsigned char Flags,unsigned char *Data,int Size, unsigned char Address,unsigned char ID) +QByteArray CNetworkProtocol::GetTxPacket(unsigned char MessageID, unsigned char Flags, unsigned char *Data, int Size, unsigned char Address, unsigned char ID) { - - int toto; - char temp; + int toto; + char temp; char OutBuffer[MAX_MESSAGE_SIZE+10]; - int FrameSize = Size + 9; //Add header data... + int FrameSize = Size + 9; //Add header data... - OutBuffer[0] = (char)FRAME_HEADER; //header - OutBuffer[1] = 1; //PC address - OutBuffer[2] = ID_PC; //PC ID - OutBuffer[3] = (char)ID; //destination ID - OutBuffer[4] = (char)Address; //Destination Address - OutBuffer[5] = (char)Flags; - OutBuffer[6] = (char)MessageID; //Cmd - toto = FrameSize & 0xFF00; - temp = FrameSize >> 8; + OutBuffer[0] = (char)FRAME_HEADER; //header + OutBuffer[1] = 1; //MasterCtrl address + OutBuffer[2] = ID_MASTER; //MasterCtrl ID + OutBuffer[3] = (char)ID; //destination ID + OutBuffer[4] = (char)Address; //Destination Address + OutBuffer[5] = (char)Flags; + OutBuffer[6] = (char)MessageID; //Cmd + toto = FrameSize & 0xFF00; + temp = FrameSize >> 8; OutBuffer[7] = ((FrameSize - 9) & 0xFF00) >> 8; OutBuffer[8] = (FrameSize - 9) & 0x00FF; - for(int i = 0; i < Size; i++) - { - temp = Data[i]; - OutBuffer[i+9] = temp; - } + for(int i = 0; i < Size; i++) + { + temp = Data[i]; + OutBuffer[i+9] = temp; + } - OutBuffer[FrameSize] = CalcCRC(OutBuffer,FrameSize); + OutBuffer[FrameSize] = CalcCRC(OutBuffer,FrameSize); // CSerialComm::instance()->WriteData(&OutBuffer[0],FrameSize+1); - return 0; + return QByteArray(OutBuffer,FrameSize); } +//int CNetworkProtocol::TxData(unsigned char MessageID,unsigned char Flags,unsigned char *Data,int Size, unsigned char Address,unsigned char ID) +//{ + +// int toto; +// char temp; +// char OutBuffer[MAX_MESSAGE_SIZE+10]; + +// int FrameSize = Size + 9; //Add header data... + +// OutBuffer[0] = (char)FRAME_HEADER; //header +// OutBuffer[1] = 1; //MasterCtrl address +// OutBuffer[2] = ID_MASTER; //MasterCtrl ID +// OutBuffer[3] = (char)ID; //destination ID +// OutBuffer[4] = (char)Address; //Destination Address +// OutBuffer[5] = (char)Flags; +// OutBuffer[6] = (char)MessageID; //Cmd +// toto = FrameSize & 0xFF00; +// temp = FrameSize >> 8; +// OutBuffer[7] = ((FrameSize - 9) & 0xFF00) >> 8; +// OutBuffer[8] = (FrameSize - 9) & 0x00FF; + +// for(int i = 0; i < Size; i++) +// { +// temp = Data[i]; +// OutBuffer[i+9] = temp; +// } + +// OutBuffer[FrameSize] = CalcCRC(OutBuffer,FrameSize); + + +//// CSerialComm::instance()->WriteData(&OutBuffer[0],FrameSize+1); + +// return 0; +//} + //void CNetworkProtocol::ReadPort(void) //{ // int Size = 0; @@ -218,6 +252,7 @@ void CNetworkProtocol::RxStateMachine(unsigned char Data) //Data is OK... execute // ExecuteCommand(); + mParentHandle->NewFrameReceived(QByteArray(mRxData,RxSize+10)); ResetRxStateMachine(); break; } diff --git a/Sources/NetworkProtocol.h b/Sources/NetworkProtocol.h index abfd9d5..071a9e4 100644 --- a/Sources/NetworkProtocol.h +++ b/Sources/NetworkProtocol.h @@ -3,17 +3,21 @@ #include "GlobalDefine.h" #include "ProtocolDefs.h" +#include "AbstractNetworkInterface.h" class CNetworkProtocol { public: - CNetworkProtocol(); + CNetworkProtocol(CAbstractNetworkCommIF *Parent); ~CNetworkProtocol(); + CAbstractNetworkCommIF *mParentHandle; + QByteArray GetTxPacket(unsigned char MessageID,unsigned char Flags,unsigned char *Data,int Size, unsigned char Address,unsigned char ID); private: void ResetRxStateMachine(); unsigned char CalcCRC(char *Buffer, int Size); - int TxData(unsigned char MessageID,unsigned char Flags,unsigned char *Data,int Size, unsigned char Address,unsigned char ID); + // int TxData(unsigned char MessageID,unsigned char Flags,unsigned char *Data,int Size, unsigned char Address,unsigned char ID); + void RxStateMachine(unsigned char Data); //State Machine states diff --git a/Sources/main.cpp b/Sources/main.cpp index 964627f..a98df80 100644 --- a/Sources/main.cpp +++ b/Sources/main.cpp @@ -32,7 +32,7 @@ int main(int argc, char *argv[]) { - QApplication::setGraphicsSystem("raster"); + //QApplication::setGraphicsSystem("raster"); //Qt Mainframe application instance. QApplication a(argc, argv); diff --git a/Sources/qextserialport/qextserialport.cpp b/Sources/qextserialport/qextserialport.cpp new file mode 100644 index 0000000..ccf3598 --- /dev/null +++ b/Sources/qextserialport/qextserialport.cpp @@ -0,0 +1,254 @@ + + +#include +#include "qextserialport.h" + +/*! +Default constructor. Note that the name of the device used by a QextSerialPort constructed with +this constructor will be determined by #defined constants, or lack thereof - the default behavior +is the same as _TTY_LINUX_. Possible naming conventions and their associated constants are: + +\verbatim + +Constant Used By Naming Convention +---------- ------------- ------------------------ +Q_OS_WIN Windows COM1, COM2 +_TTY_IRIX_ SGI/IRIX /dev/ttyf1, /dev/ttyf2 +_TTY_HPUX_ HP-UX /dev/tty1p0, /dev/tty2p0 +_TTY_SUN_ SunOS/Solaris /dev/ttya, /dev/ttyb +_TTY_DIGITAL_ Digital UNIX /dev/tty01, /dev/tty02 +_TTY_FREEBSD_ FreeBSD /dev/ttyd0, /dev/ttyd1 +_TTY_OPENBSD_ OpenBSD /dev/tty00, /dev/tty01 +_TTY_LINUX_ Linux /dev/ttyS0, /dev/ttyS1 + Linux /dev/ttyS0, /dev/ttyS1 +\endverbatim + +This constructor assigns the device name to the name of the first port on the specified system. +See the other constructors if you need to open a different port. +*/ +QextSerialPort::QextSerialPort(QextSerialPort::QueryMode mode) + : QIODevice() +{ + +#ifdef Q_OS_WIN + setPortName("COM1"); + +#elif defined(_TTY_IRIX_) + setPortName("/dev/ttyf1"); + +#elif defined(_TTY_HPUX_) + setPortName("/dev/tty1p0"); + +#elif defined(_TTY_SUN_) + setPortName("/dev/ttya"); + +#elif defined(_TTY_DIGITAL_) + setPortName("/dev/tty01"); + +#elif defined(_TTY_FREEBSD_) + setPortName("/dev/ttyd1"); + +#elif defined(_TTY_OPENBSD_) + setPortName("/dev/tty00"); + +#else + setPortName("/dev/ttyS0"); +#endif + + construct(); + setQueryMode(mode); + platformSpecificInit(); +} + +/*! +Constructs a serial port attached to the port specified by name. +name is the name of the device, which is windowsystem-specific, +e.g."COM1" or "/dev/ttyS0". +*/ +QextSerialPort::QextSerialPort(const QString & name, QextSerialPort::QueryMode mode) + : QIODevice() +{ + construct(); + setQueryMode(mode); + setPortName(name); + platformSpecificInit(); +} + +/*! +Constructs a port with default name and specified settings. +*/ +QextSerialPort::QextSerialPort(const PortSettings& settings, QextSerialPort::QueryMode mode) + : QIODevice() +{ + construct(); + setBaudRate(settings.BaudRate); + setDataBits(settings.DataBits); + setParity(settings.Parity); + setStopBits(settings.StopBits); + setFlowControl(settings.FlowControl); + setTimeout(settings.Timeout_Millisec); + setQueryMode(mode); + platformSpecificInit(); +} + +/*! +Constructs a port with specified name and settings. +*/ +QextSerialPort::QextSerialPort(const QString & name, const PortSettings& settings, QextSerialPort::QueryMode mode) + : QIODevice() +{ + construct(); + setPortName(name); + setBaudRate(settings.BaudRate); + setDataBits(settings.DataBits); + setParity(settings.Parity); + setStopBits(settings.StopBits); + setFlowControl(settings.FlowControl); + setTimeout(settings.Timeout_Millisec); + setQueryMode(mode); + platformSpecificInit(); +} + +/*! +Common constructor function for setting up default port settings. +(115200 Baud, 8N1, Hardware flow control where supported, otherwise no flow control, and 0 ms timeout). +*/ +void QextSerialPort::construct() +{ + lastErr = E_NO_ERROR; + Settings.BaudRate=BAUD115200; + Settings.DataBits=DATA_8; + Settings.Parity=PAR_NONE; + Settings.StopBits=STOP_1; + Settings.FlowControl=FLOW_HARDWARE; + Settings.Timeout_Millisec=500; + mutex = new QMutex( QMutex::Recursive ); + setOpenMode(QIODevice::NotOpen); +} + +void QextSerialPort::setQueryMode(QueryMode mechanism) +{ + _queryMode = mechanism; +} + +/*! +Sets the name of the device associated with the object, e.g. "COM1", or "/dev/ttyS0". +*/ +void QextSerialPort::setPortName(const QString & name) +{ + #ifdef Q_OS_WIN + port = fullPortNameWin( name ); + #else + port = name; + #endif +} + +/*! +Returns the name set by setPortName(). +*/ +QString QextSerialPort::portName() const +{ + return port; +} + +/*! + Reads all available data from the device, and returns it as a QByteArray. + This function has no way of reporting errors; returning an empty QByteArray() + can mean either that no data was currently available for reading, or that an error occurred. +*/ +QByteArray QextSerialPort::readAll() +{ + int avail = this->bytesAvailable(); + return (avail > 0) ? this->read(avail) : QByteArray(); +} + +/*! +Returns the baud rate of the serial port. For a list of possible return values see +the definition of the enum BaudRateType. +*/ +BaudRateType QextSerialPort::baudRate(void) const +{ + return Settings.BaudRate; +} + +/*! +Returns the number of data bits used by the port. For a list of possible values returned by +this function, see the definition of the enum DataBitsType. +*/ +DataBitsType QextSerialPort::dataBits() const +{ + return Settings.DataBits; +} + +/*! +Returns the type of parity used by the port. For a list of possible values returned by +this function, see the definition of the enum ParityType. +*/ +ParityType QextSerialPort::parity() const +{ + return Settings.Parity; +} + +/*! +Returns the number of stop bits used by the port. For a list of possible return values, see +the definition of the enum StopBitsType. +*/ +StopBitsType QextSerialPort::stopBits() const +{ + return Settings.StopBits; +} + +/*! +Returns the type of flow control used by the port. For a list of possible values returned +by this function, see the definition of the enum FlowType. +*/ +FlowType QextSerialPort::flowControl() const +{ + return Settings.FlowControl; +} + +/*! +Returns true if device is sequential, otherwise returns false. Serial port is sequential device +so this function always returns true. Check QIODevice::isSequential() documentation for more +information. +*/ +bool QextSerialPort::isSequential() const +{ + return true; +} + +QString QextSerialPort::errorString() +{ + switch(lastErr) + { + case E_NO_ERROR: return "No Error has occurred"; + case E_INVALID_FD: return "Invalid file descriptor (port was not opened correctly)"; + case E_NO_MEMORY: return "Unable to allocate memory tables (POSIX)"; + case E_CAUGHT_NON_BLOCKED_SIGNAL: return "Caught a non-blocked signal (POSIX)"; + case E_PORT_TIMEOUT: return "Operation timed out (POSIX)"; + case E_INVALID_DEVICE: return "The file opened by the port is not a valid device"; + case E_BREAK_CONDITION: return "The port detected a break condition"; + case E_FRAMING_ERROR: return "The port detected a framing error (usually caused by incorrect baud rate settings)"; + case E_IO_ERROR: return "There was an I/O error while communicating with the port"; + case E_BUFFER_OVERRUN: return "Character buffer overrun"; + case E_RECEIVE_OVERFLOW: return "Receive buffer overflow"; + case E_RECEIVE_PARITY_ERROR: return "The port detected a parity error in the received data"; + case E_TRANSMIT_OVERFLOW: return "Transmit buffer overflow"; + case E_READ_FAILED: return "General read operation failure"; + case E_WRITE_FAILED: return "General write operation failure"; + case E_FILE_NOT_FOUND: return "The "+this->portName()+" file doesn't exists"; + default: return QString("Unknown error: %1").arg(lastErr); + } +} + +/*! +Standard destructor. +*/ +QextSerialPort::~QextSerialPort() +{ + if (isOpen()) { + close(); + } + platformSpecificDestruct(); + delete mutex; +} diff --git a/Sources/qextserialport/qextserialport.h b/Sources/qextserialport/qextserialport.h new file mode 100644 index 0000000..13a0db5 --- /dev/null +++ b/Sources/qextserialport/qextserialport.h @@ -0,0 +1,333 @@ + +#ifndef _QEXTSERIALPORT_H_ +#define _QEXTSERIALPORT_H_ + +#include "qextserialport_global.h" + +/*if all warning messages are turned off, flag portability warnings to be turned off as well*/ +#ifdef _TTY_NOWARN_ +#define _TTY_NOWARN_PORT_ +#endif + +/*macros for warning and debug messages*/ +#ifdef _TTY_NOWARN_PORT_ +#define TTY_PORTABILITY_WARNING(s) +#else +#define TTY_PORTABILITY_WARNING(s) qWarning(s) +#endif /*_TTY_NOWARN_PORT_*/ +#ifdef _TTY_NOWARN_ +#define TTY_WARNING(s) +#else +#define TTY_WARNING(s) qWarning(s) +#endif /*_TTY_NOWARN_*/ + + +/*line status constants*/ +#define LS_CTS 0x01 +#define LS_DSR 0x02 +#define LS_DCD 0x04 +#define LS_RI 0x08 +#define LS_RTS 0x10 +#define LS_DTR 0x20 +#define LS_ST 0x40 +#define LS_SR 0x80 + +/*error constants*/ +#define E_NO_ERROR 0 +#define E_INVALID_FD 1 +#define E_NO_MEMORY 2 +#define E_CAUGHT_NON_BLOCKED_SIGNAL 3 +#define E_PORT_TIMEOUT 4 +#define E_INVALID_DEVICE 5 +#define E_BREAK_CONDITION 6 +#define E_FRAMING_ERROR 7 +#define E_IO_ERROR 8 +#define E_BUFFER_OVERRUN 9 +#define E_RECEIVE_OVERFLOW 10 +#define E_RECEIVE_PARITY_ERROR 11 +#define E_TRANSMIT_OVERFLOW 12 +#define E_READ_FAILED 13 +#define E_WRITE_FAILED 14 +#define E_FILE_NOT_FOUND 15 + +enum BaudRateType +{ + BAUD50, //POSIX ONLY + BAUD75, //POSIX ONLY + BAUD110, + BAUD134, //POSIX ONLY + BAUD150, //POSIX ONLY + BAUD200, //POSIX ONLY + BAUD300, + BAUD600, + BAUD1200, + BAUD1800, //POSIX ONLY + BAUD2400, + BAUD4800, + BAUD9600, + BAUD14400, //WINDOWS ONLY + BAUD19200, + BAUD38400, + BAUD56000, //WINDOWS ONLY + BAUD57600, + BAUD76800, //POSIX ONLY + BAUD115200, + BAUD128000, //WINDOWS ONLY + BAUD256000 //WINDOWS ONLY +}; + +enum DataBitsType +{ + DATA_5, + DATA_6, + DATA_7, + DATA_8 +}; + +enum ParityType +{ + PAR_NONE, + PAR_ODD, + PAR_EVEN, + PAR_MARK, //WINDOWS ONLY + PAR_SPACE +}; + +enum StopBitsType +{ + STOP_1, + STOP_1_5, //WINDOWS ONLY + STOP_2 +}; + +enum FlowType +{ + FLOW_OFF, + FLOW_HARDWARE, + FLOW_XONXOFF +}; + +/** + * structure to contain port settings + */ +struct PortSettings +{ + BaudRateType BaudRate; + DataBitsType DataBits; + ParityType Parity; + StopBitsType StopBits; + FlowType FlowControl; + long Timeout_Millisec; +}; + +#include +#include +#ifdef Q_OS_UNIX +#include +#include +#include +#include +#include +#include +#include +#include +#elif (defined Q_OS_WIN) +#include +#include +#include +#include +#endif + +/*! +Encapsulates a serial port on both POSIX and Windows systems. + +\note +Be sure to check the full list of members, as QIODevice provides quite a lot of +functionality for QextSerialPort. + +\section Usage +QextSerialPort offers both a polling and event driven API. Event driven is typically easier +to use, since you never have to worry about checking for new data. + +\b Example +\code +QextSerialPort* port = new QextSerialPort("COM1", QextSerialPort::EventDriven); +connect(port, SIGNAL(readyRead()), myClass, SLOT(onDataAvailable())); +port->open(); + +void MyClass::onDataAvailable() { + int avail = port->bytesAvailable(); + if( avail > 0 ) { + QByteArray usbdata; + usbdata.resize(avail); + int read = port->read(usbdata.data(), usbdata.size()); + if( read > 0 ) { + processNewData(usbdata); + } + } +} +\endcode + +\section Compatibility +The user will be notified of errors and possible portability conflicts at run-time +by default - this behavior can be turned off by defining _TTY_NOWARN_ +(to turn off all warnings) or _TTY_NOWARN_PORT_ (to turn off portability warnings) in the project. + +On Windows NT/2000/XP this class uses Win32 serial port functions by default. The user may +select POSIX behavior under NT, 2000, or XP ONLY by defining Q_OS_UNIX in the project. +No guarantees are made as to the quality of POSIX support under NT/2000 however. + +\author Stefan Sander, Michal Policht, Brandon Fosdick, Liam Staskawicz +*/ +class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice +{ + Q_OBJECT + public: + enum QueryMode { + Polling, + EventDriven + }; + + QextSerialPort(QueryMode mode = EventDriven); + QextSerialPort(const QString & name, QueryMode mode = EventDriven); + QextSerialPort(PortSettings const& s, QueryMode mode = EventDriven); + QextSerialPort(const QString & name, PortSettings const& s, QueryMode mode = EventDriven); + ~QextSerialPort(); + + void setPortName(const QString & name); + QString portName() const; + + /**! + * Get query mode. + * \return query mode. + */ + inline QueryMode queryMode() const { return _queryMode; } + + /*! + * Set desired serial communication handling style. You may choose from polling + * or event driven approach. This function does nothing when port is open; to + * apply changes port must be reopened. + * + * In event driven approach read() and write() functions are acting + * asynchronously. They return immediately and the operation is performed in + * the background, so they doesn't freeze the calling thread. + * To determine when operation is finished, QextSerialPort runs separate thread + * and monitors serial port events. Whenever the event occurs, adequate signal + * is emitted. + * + * When polling is set, read() and write() are acting synchronously. Signals are + * not working in this mode and some functions may not be available. The advantage + * of polling is that it generates less overhead due to lack of signals emissions + * and it doesn't start separate thread to monitor events. + * + * Generally event driven approach is more capable and friendly, although some + * applications may need as low overhead as possible and then polling comes. + * + * \param mode query mode. + */ + void setQueryMode(QueryMode mode); + + void setBaudRate(BaudRateType); + BaudRateType baudRate() const; + + void setDataBits(DataBitsType); + DataBitsType dataBits() const; + + void setParity(ParityType); + ParityType parity() const; + + void setStopBits(StopBitsType); + StopBitsType stopBits() const; + + void setFlowControl(FlowType); + FlowType flowControl() const; + + void setTimeout(long); + + bool open(OpenMode mode); + bool isSequential() const; + void close(); + void flush(); + + qint64 size() const; + qint64 bytesAvailable() const; + QByteArray readAll(); + + void ungetChar(char c); + + ulong lastError() const; + void translateError(ulong error); + + void setDtr(bool set=true); + void setRts(bool set=true); + ulong lineStatus(); + QString errorString(); + +#ifdef Q_OS_WIN + virtual bool waitForReadyRead(int msecs); ///< @todo implement. + virtual qint64 bytesToWrite() const; + static QString fullPortNameWin(const QString & name); +#endif + + protected: + QMutex* mutex; + QString port; + PortSettings Settings; + ulong lastErr; + QueryMode _queryMode; + + // platform specific members +#ifdef Q_OS_UNIX + int fd; + QSocketNotifier *readNotifier; + struct termios Posix_CommConfig; + struct termios old_termios; + struct timeval Posix_Timeout; + struct timeval Posix_Copy_Timeout; +#elif (defined Q_OS_WIN) + HANDLE Win_Handle; + OVERLAPPED overlap; + COMMCONFIG Win_CommConfig; + COMMTIMEOUTS Win_CommTimeouts; + QWinEventNotifier *winEventNotifier; + DWORD eventMask; + QList pendingWrites; + QReadWriteLock* bytesToWriteLock; + qint64 _bytesToWrite; +#endif + + void construct(); // common construction + void platformSpecificDestruct(); + void platformSpecificInit(); + qint64 readData(char * data, qint64 maxSize); + qint64 writeData(const char * data, qint64 maxSize); + +#ifdef Q_OS_WIN + private slots: + void onWinEvent(HANDLE h); +#endif + + private: + Q_DISABLE_COPY(QextSerialPort) + + signals: +// /** +// * This signal is emitted whenever port settings are updated. +// * \param valid \p true if settings are valid, \p false otherwise. +// * +// * @todo implement. +// */ +// // void validSettings(bool valid); + + /*! + * This signal is emitted whenever dsr line has changed its state. You may + * use this signal to check if device is connected. + * \param status \p true when DSR signal is on, \p false otherwise. + * + * \see lineStatus(). + */ + void dsrChanged(bool status); + +}; + +#endif diff --git a/Sources/qextserialport/qextserialport_global.h b/Sources/qextserialport/qextserialport_global.h new file mode 100644 index 0000000..63ad657 --- /dev/null +++ b/Sources/qextserialport/qextserialport_global.h @@ -0,0 +1,18 @@ + + +#ifndef QEXTSERIALPORT_GLOBAL_H +#define QEXTSERIALPORT_GLOBAL_H + +#include + +#ifdef QEXTSERIALPORT_LIB +# define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT +#else +# define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT +#endif + +#undef QEXTSERIALPORT_EXPORT +#define QEXTSERIALPORT_EXPORT + +#endif // QEXTSERIALPORT_GLOBAL_H + diff --git a/Sources/qextserialport/qwineventnotifier_p.h b/Sources/qextserialport/qwineventnotifier_p.h new file mode 100644 index 0000000..459cd67 --- /dev/null +++ b/Sources/qextserialport/qwineventnotifier_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINEVENTNOTIFIER_P_H +#define QWINEVENTNOTIFIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qt_windows.h" + +QT_BEGIN_NAMESPACE + +class Q_CORE_EXPORT QWinEventNotifier : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + explicit QWinEventNotifier(QObject *parent = 0); + explicit QWinEventNotifier(HANDLE hEvent, QObject *parent = 0); + ~QWinEventNotifier(); + + void setHandle(HANDLE hEvent); + HANDLE handle() const; + + bool isEnabled() const; + +public Q_SLOTS: + void setEnabled(bool enable); + +Q_SIGNALS: + void activated(HANDLE hEvent); + +protected: + bool event(QEvent * e); + +private: + Q_DISABLE_COPY(QWinEventNotifier) + + HANDLE handleToEvent; + bool enabled; +}; + +QT_END_NAMESPACE + +#endif // QWINEVENTNOTIFIER_P_H diff --git a/Sources/qextserialport/win_qextserialport.cpp b/Sources/qextserialport/win_qextserialport.cpp new file mode 100644 index 0000000..af1cdb6 --- /dev/null +++ b/Sources/qextserialport/win_qextserialport.cpp @@ -0,0 +1,868 @@ + + +#include +#include +#include +#include "qextserialport.h" + +void QextSerialPort::platformSpecificInit() +{ + Win_Handle=INVALID_HANDLE_VALUE; + ZeroMemory(&overlap, sizeof(OVERLAPPED)); + overlap.hEvent = CreateEvent(NULL, true, false, NULL); + winEventNotifier = 0; + bytesToWriteLock = new QReadWriteLock; + _bytesToWrite = 0; +} + +/*! +Standard destructor. +*/ +void QextSerialPort::platformSpecificDestruct() { + CloseHandle(overlap.hEvent); + delete bytesToWriteLock; +} + +QString QextSerialPort::fullPortNameWin(const QString & name) +{ + QRegExp rx("^COM(\\d+)"); + QString fullName(name); + if(fullName.contains(rx)) { + int portnum = rx.cap(1).toInt(); + if(portnum > 9) // COM ports greater than 9 need \\.\ prepended + fullName.prepend("\\\\.\\"); + } + return fullName; +} + +/*! +Opens a serial port. Note that this function does not specify which device to open. If you need +to open a device by name, see QextSerialPort::open(const char*). This function has no effect +if the port associated with the class is already open. The port is also configured to the current +settings, as stored in the Settings structure. +*/ +bool QextSerialPort::open(OpenMode mode) { + unsigned long confSize = sizeof(COMMCONFIG); + Win_CommConfig.dwSize = confSize; + DWORD dwFlagsAndAttributes = 0; + if (queryMode() == QextSerialPort::EventDriven) + dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED; + + QMutexLocker lock(mutex); + if (mode == QIODevice::NotOpen) + return isOpen(); + if (!isOpen()) { + /*open the port*/ + Win_Handle=CreateFileA(port.toAscii(), GENERIC_READ|GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); + if (Win_Handle!=INVALID_HANDLE_VALUE) { + QIODevice::open(mode); + /*configure port settings*/ + GetCommConfig(Win_Handle, &Win_CommConfig, &confSize); + GetCommState(Win_Handle, &(Win_CommConfig.dcb)); + + /*set up parameters*/ + Win_CommConfig.dcb.fBinary=TRUE; + Win_CommConfig.dcb.fInX=FALSE; + Win_CommConfig.dcb.fOutX=FALSE; + Win_CommConfig.dcb.fAbortOnError=FALSE; + Win_CommConfig.dcb.fNull=FALSE; + setBaudRate(Settings.BaudRate); + setDataBits(Settings.DataBits); + setStopBits(Settings.StopBits); + setParity(Settings.Parity); + setFlowControl(Settings.FlowControl); + setTimeout(Settings.Timeout_Millisec); + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + + //init event driven approach + if (queryMode() == QextSerialPort::EventDriven) { + Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD; + Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0; + Win_CommTimeouts.ReadTotalTimeoutConstant = 0; + Win_CommTimeouts.WriteTotalTimeoutMultiplier = 0; + Win_CommTimeouts.WriteTotalTimeoutConstant = 0; + SetCommTimeouts(Win_Handle, &Win_CommTimeouts); + if (!SetCommMask( Win_Handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) { + qWarning() << "failed to set Comm Mask. Error code:", GetLastError(); + return false; + } + winEventNotifier = new QWinEventNotifier(overlap.hEvent, this); + connect(winEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(onWinEvent(HANDLE))); + WaitCommEvent(Win_Handle, &eventMask, &overlap); + } + } + } else { + return false; + } + return isOpen(); +} + +/*! +Closes a serial port. This function has no effect if the serial port associated with the class +is not currently open. +*/ +void QextSerialPort::close() +{ + QMutexLocker lock(mutex); + if (isOpen()) { + flush(); + QIODevice::close(); // mark ourselves as closed + CancelIo(Win_Handle); + if (CloseHandle(Win_Handle)) + Win_Handle = INVALID_HANDLE_VALUE; + if (winEventNotifier) + winEventNotifier->deleteLater(); + + _bytesToWrite = 0; + + foreach(OVERLAPPED* o, pendingWrites) { + CloseHandle(o->hEvent); + delete o; + } + pendingWrites.clear(); + } +} + +/*! +Flushes all pending I/O to the serial port. This function has no effect if the serial port +associated with the class is not currently open. +*/ +void QextSerialPort::flush() { + QMutexLocker lock(mutex); + if (isOpen()) { + FlushFileBuffers(Win_Handle); + } +} + +/*! +This function will return the number of bytes waiting in the receive queue of the serial port. +It is included primarily to provide a complete QIODevice interface, and will not record errors +in the lastErr member (because it is const). This function is also not thread-safe - in +multithreading situations, use QextSerialPort::bytesAvailable() instead. +*/ +qint64 QextSerialPort::size() const { + int availBytes; + COMSTAT Win_ComStat; + DWORD Win_ErrorMask=0; + ClearCommError(Win_Handle, &Win_ErrorMask, &Win_ComStat); + availBytes = Win_ComStat.cbInQue; + return (qint64)availBytes; +} + +/*! +Returns the number of bytes waiting in the port's receive queue. This function will return 0 if +the port is not currently open, or -1 on error. +*/ +qint64 QextSerialPort::bytesAvailable() const { + QMutexLocker lock(mutex); + if (isOpen()) { + DWORD Errors; + COMSTAT Status; + if (ClearCommError(Win_Handle, &Errors, &Status)) { + return Status.cbInQue + QIODevice::bytesAvailable(); + } + return (qint64)-1; + } + return 0; +} + +/*! +Translates a system-specific error code to a QextSerialPort error code. Used internally. +*/ +void QextSerialPort::translateError(ulong error) { + if (error&CE_BREAK) { + lastErr=E_BREAK_CONDITION; + } + else if (error&CE_FRAME) { + lastErr=E_FRAMING_ERROR; + } + else if (error&CE_IOE) { + lastErr=E_IO_ERROR; + } + else if (error&CE_MODE) { + lastErr=E_INVALID_FD; + } + else if (error&CE_OVERRUN) { + lastErr=E_BUFFER_OVERRUN; + } + else if (error&CE_RXPARITY) { + lastErr=E_RECEIVE_PARITY_ERROR; + } + else if (error&CE_RXOVER) { + lastErr=E_RECEIVE_OVERFLOW; + } + else if (error&CE_TXFULL) { + lastErr=E_TRANSMIT_OVERFLOW; + } +} + +/*! +Reads a block of data from the serial port. This function will read at most maxlen bytes from +the serial port and place them in the buffer pointed to by data. Return value is the number of +bytes actually read, or -1 on error. + +\warning before calling this function ensure that serial port associated with this class +is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::readData(char *data, qint64 maxSize) +{ + DWORD retVal; + QMutexLocker lock(mutex); + retVal = 0; + if (queryMode() == QextSerialPort::EventDriven) { + OVERLAPPED overlapRead; + ZeroMemory(&overlapRead, sizeof(OVERLAPPED)); + if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & retVal, & overlapRead)) { + if (GetLastError() == ERROR_IO_PENDING) + GetOverlappedResult(Win_Handle, & overlapRead, & retVal, true); + else { + lastErr = E_READ_FAILED; + retVal = (DWORD)-1; + } + } + } else if (!ReadFile(Win_Handle, (void*)data, (DWORD)maxSize, & retVal, NULL)) { + lastErr = E_READ_FAILED; + retVal = (DWORD)-1; + } + return (qint64)retVal; +} + +/*! +Writes a block of data to the serial port. This function will write len bytes +from the buffer pointed to by data to the serial port. Return value is the number +of bytes actually written, or -1 on error. + +\warning before calling this function ensure that serial port associated with this class +is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::writeData(const char *data, qint64 maxSize) +{ + QMutexLocker lock( mutex ); + DWORD retVal = 0; + if (queryMode() == QextSerialPort::EventDriven) { + OVERLAPPED* newOverlapWrite = new OVERLAPPED; + ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED)); + newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL); + if (WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & retVal, newOverlapWrite)) { + CloseHandle(newOverlapWrite->hEvent); + delete newOverlapWrite; + } + else if (GetLastError() == ERROR_IO_PENDING) { + // writing asynchronously...not an error + QWriteLocker writelocker(bytesToWriteLock); + _bytesToWrite += maxSize; + pendingWrites.append(newOverlapWrite); + } + else { + qDebug() << "serialport write error:" << GetLastError(); + lastErr = E_WRITE_FAILED; + retVal = (DWORD)-1; + if(!CancelIo(newOverlapWrite->hEvent)) + qDebug() << "serialport: couldn't cancel IO"; + if(!CloseHandle(newOverlapWrite->hEvent)) + qDebug() << "serialport: couldn't close OVERLAPPED handle"; + delete newOverlapWrite; + } + } else if (!WriteFile(Win_Handle, (void*)data, (DWORD)maxSize, & retVal, NULL)) { + lastErr = E_WRITE_FAILED; + retVal = (DWORD)-1; + } + return (qint64)retVal; +} + +/*! +This function is included to implement the full QIODevice interface, and currently has no +purpose within this class. This function is meaningless on an unbuffered device and currently +only prints a warning message to that effect. +*/ +void QextSerialPort::ungetChar(char c) { + + /*meaningless on unbuffered sequential device - return error and print a warning*/ + TTY_WARNING("QextSerialPort: ungetChar() called on an unbuffered sequential device - operation is meaningless"); +} + +/*! +Sets the flow control used by the port. Possible values of flow are: +\verbatim + FLOW_OFF No flow control + FLOW_HARDWARE Hardware (RTS/CTS) flow control + FLOW_XONXOFF Software (XON/XOFF) flow control +\endverbatim +*/ +void QextSerialPort::setFlowControl(FlowType flow) { + QMutexLocker lock(mutex); + if (Settings.FlowControl!=flow) { + Settings.FlowControl=flow; + } + if (isOpen()) { + switch(flow) { + + /*no flow control*/ + case FLOW_OFF: + Win_CommConfig.dcb.fOutxCtsFlow=FALSE; + Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE; + Win_CommConfig.dcb.fInX=FALSE; + Win_CommConfig.dcb.fOutX=FALSE; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + break; + + /*software (XON/XOFF) flow control*/ + case FLOW_XONXOFF: + Win_CommConfig.dcb.fOutxCtsFlow=FALSE; + Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_DISABLE; + Win_CommConfig.dcb.fInX=TRUE; + Win_CommConfig.dcb.fOutX=TRUE; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + break; + + case FLOW_HARDWARE: + Win_CommConfig.dcb.fOutxCtsFlow=TRUE; + Win_CommConfig.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE; + Win_CommConfig.dcb.fInX=FALSE; + Win_CommConfig.dcb.fOutX=FALSE; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + break; + } + } +} + +/*! +Sets the parity associated with the serial port. The possible values of parity are: +\verbatim + PAR_SPACE Space Parity + PAR_MARK Mark Parity + PAR_NONE No Parity + PAR_EVEN Even Parity + PAR_ODD Odd Parity +\endverbatim +*/ +void QextSerialPort::setParity(ParityType parity) { + QMutexLocker lock(mutex); + if (Settings.Parity!=parity) { + Settings.Parity=parity; + } + if (isOpen()) { + Win_CommConfig.dcb.Parity=(unsigned char)parity; + switch (parity) { + + /*space parity*/ + case PAR_SPACE: + if (Settings.DataBits==DATA_8) { + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: Space parity with 8 data bits is not supported by POSIX systems."); + } + Win_CommConfig.dcb.fParity=TRUE; + break; + + /*mark parity - WINDOWS ONLY*/ + case PAR_MARK: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: Mark parity is not supported by POSIX systems"); + Win_CommConfig.dcb.fParity=TRUE; + break; + + /*no parity*/ + case PAR_NONE: + Win_CommConfig.dcb.fParity=FALSE; + break; + + /*even parity*/ + case PAR_EVEN: + Win_CommConfig.dcb.fParity=TRUE; + break; + + /*odd parity*/ + case PAR_ODD: + Win_CommConfig.dcb.fParity=TRUE; + break; + } + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } +} + +/*! +Sets the number of data bits used by the serial port. Possible values of dataBits are: +\verbatim + DATA_5 5 data bits + DATA_6 6 data bits + DATA_7 7 data bits + DATA_8 8 data bits +\endverbatim + +\note +This function is subject to the following restrictions: +\par + 5 data bits cannot be used with 2 stop bits. +\par + 1.5 stop bits can only be used with 5 data bits. +\par + 8 data bits cannot be used with space parity on POSIX systems. +*/ +void QextSerialPort::setDataBits(DataBitsType dataBits) { + QMutexLocker lock(mutex); + if (Settings.DataBits!=dataBits) { + if ((Settings.StopBits==STOP_2 && dataBits==DATA_5) || + (Settings.StopBits==STOP_1_5 && dataBits!=DATA_5)) { + } + else { + Settings.DataBits=dataBits; + } + } + if (isOpen()) { + switch(dataBits) { + + /*5 data bits*/ + case DATA_5: + if (Settings.StopBits==STOP_2) { + TTY_WARNING("QextSerialPort: 5 Data bits cannot be used with 2 stop bits."); + } + else { + Win_CommConfig.dcb.ByteSize=5; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + + /*6 data bits*/ + case DATA_6: + if (Settings.StopBits==STOP_1_5) { + TTY_WARNING("QextSerialPort: 6 Data bits cannot be used with 1.5 stop bits."); + } + else { + Win_CommConfig.dcb.ByteSize=6; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + + /*7 data bits*/ + case DATA_7: + if (Settings.StopBits==STOP_1_5) { + TTY_WARNING("QextSerialPort: 7 Data bits cannot be used with 1.5 stop bits."); + } + else { + Win_CommConfig.dcb.ByteSize=7; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + + /*8 data bits*/ + case DATA_8: + if (Settings.StopBits==STOP_1_5) { + TTY_WARNING("QextSerialPort: 8 Data bits cannot be used with 1.5 stop bits."); + } + else { + Win_CommConfig.dcb.ByteSize=8; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + } + } +} + +/*! +Sets the number of stop bits used by the serial port. Possible values of stopBits are: +\verbatim + STOP_1 1 stop bit + STOP_1_5 1.5 stop bits + STOP_2 2 stop bits +\endverbatim + +\note +This function is subject to the following restrictions: +\par + 2 stop bits cannot be used with 5 data bits. +\par + 1.5 stop bits cannot be used with 6 or more data bits. +\par + POSIX does not support 1.5 stop bits. +*/ +void QextSerialPort::setStopBits(StopBitsType stopBits) { + QMutexLocker lock(mutex); + if (Settings.StopBits!=stopBits) { + if ((Settings.DataBits==DATA_5 && stopBits==STOP_2) || + (stopBits==STOP_1_5 && Settings.DataBits!=DATA_5)) { + } + else { + Settings.StopBits=stopBits; + } + } + if (isOpen()) { + switch (stopBits) { + + /*one stop bit*/ + case STOP_1: + Win_CommConfig.dcb.StopBits=ONESTOPBIT; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + break; + + /*1.5 stop bits*/ + case STOP_1_5: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: 1.5 stop bit operation is not supported by POSIX."); + if (Settings.DataBits!=DATA_5) { + TTY_WARNING("QextSerialPort: 1.5 stop bits can only be used with 5 data bits"); + } + else { + Win_CommConfig.dcb.StopBits=ONE5STOPBITS; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + + /*two stop bits*/ + case STOP_2: + if (Settings.DataBits==DATA_5) { + TTY_WARNING("QextSerialPort: 2 stop bits cannot be used with 5 data bits"); + } + else { + Win_CommConfig.dcb.StopBits=TWOSTOPBITS; + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } + break; + } + } +} + +/*! +Sets the baud rate of the serial port. Note that not all rates are applicable on +all platforms. The following table shows translations of the various baud rate +constants on Windows(including NT/2000) and POSIX platforms. Speeds marked with an * +are speeds that are usable on both Windows and POSIX. +\verbatim + + RATE Windows Speed POSIX Speed + ----------- ------------- ----------- + BAUD50 110 50 + BAUD75 110 75 + *BAUD110 110 110 + BAUD134 110 134.5 + BAUD150 110 150 + BAUD200 110 200 + *BAUD300 300 300 + *BAUD600 600 600 + *BAUD1200 1200 1200 + BAUD1800 1200 1800 + *BAUD2400 2400 2400 + *BAUD4800 4800 4800 + *BAUD9600 9600 9600 + BAUD14400 14400 9600 + *BAUD19200 19200 19200 + *BAUD38400 38400 38400 + BAUD56000 56000 38400 + *BAUD57600 57600 57600 + BAUD76800 57600 76800 + *BAUD115200 115200 115200 + BAUD128000 128000 115200 + BAUD256000 256000 115200 +\endverbatim +*/ +void QextSerialPort::setBaudRate(BaudRateType baudRate) { + QMutexLocker lock(mutex); + if (Settings.BaudRate!=baudRate) { + switch (baudRate) { + case BAUD50: + case BAUD75: + case BAUD134: + case BAUD150: + case BAUD200: + Settings.BaudRate=BAUD110; + break; + + case BAUD1800: + Settings.BaudRate=BAUD1200; + break; + + case BAUD76800: + Settings.BaudRate=BAUD57600; + break; + + default: + Settings.BaudRate=baudRate; + break; + } + } + if (isOpen()) { + switch (baudRate) { + + /*50 baud*/ + case BAUD50: + TTY_WARNING("QextSerialPort: Windows does not support 50 baud operation. Switching to 110 baud."); + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*75 baud*/ + case BAUD75: + TTY_WARNING("QextSerialPort: Windows does not support 75 baud operation. Switching to 110 baud."); + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*110 baud*/ + case BAUD110: + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*134.5 baud*/ + case BAUD134: + TTY_WARNING("QextSerialPort: Windows does not support 134.5 baud operation. Switching to 110 baud."); + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*150 baud*/ + case BAUD150: + TTY_WARNING("QextSerialPort: Windows does not support 150 baud operation. Switching to 110 baud."); + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*200 baud*/ + case BAUD200: + TTY_WARNING("QextSerialPort: Windows does not support 200 baud operation. Switching to 110 baud."); + Win_CommConfig.dcb.BaudRate=CBR_110; + break; + + /*300 baud*/ + case BAUD300: + Win_CommConfig.dcb.BaudRate=CBR_300; + break; + + /*600 baud*/ + case BAUD600: + Win_CommConfig.dcb.BaudRate=CBR_600; + break; + + /*1200 baud*/ + case BAUD1200: + Win_CommConfig.dcb.BaudRate=CBR_1200; + break; + + /*1800 baud*/ + case BAUD1800: + TTY_WARNING("QextSerialPort: Windows does not support 1800 baud operation. Switching to 1200 baud."); + Win_CommConfig.dcb.BaudRate=CBR_1200; + break; + + /*2400 baud*/ + case BAUD2400: + Win_CommConfig.dcb.BaudRate=CBR_2400; + break; + + /*4800 baud*/ + case BAUD4800: + Win_CommConfig.dcb.BaudRate=CBR_4800; + break; + + /*9600 baud*/ + case BAUD9600: + Win_CommConfig.dcb.BaudRate=CBR_9600; + break; + + /*14400 baud*/ + case BAUD14400: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: POSIX does not support 14400 baud operation."); + Win_CommConfig.dcb.BaudRate=CBR_14400; + break; + + /*19200 baud*/ + case BAUD19200: + Win_CommConfig.dcb.BaudRate=CBR_19200; + break; + + /*38400 baud*/ + case BAUD38400: + Win_CommConfig.dcb.BaudRate=CBR_38400; + break; + + /*56000 baud*/ + case BAUD56000: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: POSIX does not support 56000 baud operation."); + Win_CommConfig.dcb.BaudRate=CBR_56000; + break; + + /*57600 baud*/ + case BAUD57600: + Win_CommConfig.dcb.BaudRate=CBR_57600; + break; + + /*76800 baud*/ + case BAUD76800: + TTY_WARNING("QextSerialPort: Windows does not support 76800 baud operation. Switching to 57600 baud."); + Win_CommConfig.dcb.BaudRate=CBR_57600; + break; + + /*115200 baud*/ + case BAUD115200: + Win_CommConfig.dcb.BaudRate=CBR_115200; + break; + + /*128000 baud*/ + case BAUD128000: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: POSIX does not support 128000 baud operation."); + Win_CommConfig.dcb.BaudRate=CBR_128000; + break; + + /*256000 baud*/ + case BAUD256000: + TTY_PORTABILITY_WARNING("QextSerialPort Portability Warning: POSIX does not support 256000 baud operation."); + Win_CommConfig.dcb.BaudRate=CBR_256000; + break; + } + SetCommConfig(Win_Handle, &Win_CommConfig, sizeof(COMMCONFIG)); + } +} + +/*! +Sets DTR line to the requested state (high by default). This function will have no effect if +the port associated with the class is not currently open. +*/ +void QextSerialPort::setDtr(bool set) { + QMutexLocker lock(mutex); + if (isOpen()) { + if (set) { + EscapeCommFunction(Win_Handle, SETDTR); + } + else { + EscapeCommFunction(Win_Handle, CLRDTR); + } + } +} + +/*! +Sets RTS line to the requested state (high by default). This function will have no effect if +the port associated with the class is not currently open. +*/ +void QextSerialPort::setRts(bool set) { + QMutexLocker lock(mutex); + if (isOpen()) { + if (set) { + EscapeCommFunction(Win_Handle, SETRTS); + } + else { + EscapeCommFunction(Win_Handle, CLRRTS); + } + } +} + +/*! +Returns the line status as stored by the port function. This function will retrieve the states +of the following lines: DCD, CTS, DSR, and RI. On POSIX systems, the following additional lines +can be monitored: DTR, RTS, Secondary TXD, and Secondary RXD. The value returned is an unsigned +long with specific bits indicating which lines are high. The following constants should be used +to examine the states of individual lines: + +\verbatim +Mask Line +------ ---- +LS_CTS CTS +LS_DSR DSR +LS_DCD DCD +LS_RI RI +\endverbatim + +This function will return 0 if the port associated with the class is not currently open. +*/ +ulong QextSerialPort::lineStatus(void) { + unsigned long Status=0, Temp=0; + QMutexLocker lock(mutex); + if (isOpen()) { + GetCommModemStatus(Win_Handle, &Temp); + if (Temp&MS_CTS_ON) { + Status|=LS_CTS; + } + if (Temp&MS_DSR_ON) { + Status|=LS_DSR; + } + if (Temp&MS_RING_ON) { + Status|=LS_RI; + } + if (Temp&MS_RLSD_ON) { + Status|=LS_DCD; + } + } + return Status; +} + +bool QextSerialPort::waitForReadyRead(int msecs) +{ + //@todo implement + return false; +} + +qint64 QextSerialPort::bytesToWrite() const +{ + QReadLocker rl(bytesToWriteLock); + return _bytesToWrite; +} + +/* + Triggered when there's activity on our HANDLE. +*/ +void QextSerialPort::onWinEvent(HANDLE h) +{ + QMutexLocker lock(mutex); + if(h == overlap.hEvent) { + if (eventMask & EV_RXCHAR) { + if (sender() != this && bytesAvailable() > 0) + emit readyRead(); + } + if (eventMask & EV_TXEMPTY) { + /* + A write completed. Run through the list of OVERLAPPED writes, and if + they completed successfully, take them off the list and delete them. + Otherwise, leave them on there so they can finish. + */ + qint64 totalBytesWritten = 0; + QList overlapsToDelete; + foreach(OVERLAPPED* o, pendingWrites) { + DWORD numBytes = 0; + if (GetOverlappedResult(Win_Handle, o, & numBytes, false)) { + overlapsToDelete.append(o); + totalBytesWritten += numBytes; + } else if( GetLastError() != ERROR_IO_INCOMPLETE ) { + overlapsToDelete.append(o); + qWarning() << "CommEvent overlapped write error:" << GetLastError(); + } + } + + if (sender() != this && totalBytesWritten > 0) { + QWriteLocker writelocker(bytesToWriteLock); + emit bytesWritten(totalBytesWritten); + _bytesToWrite = 0; + } + + foreach(OVERLAPPED* o, overlapsToDelete) { + OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o)); + CloseHandle(toDelete->hEvent); + delete toDelete; + } + } + if (eventMask & EV_DSR) { + if (lineStatus() & LS_DSR) + emit dsrChanged(true); + else + emit dsrChanged(false); + } + } + WaitCommEvent(Win_Handle, &eventMask, &overlap); +} + +/*! +Sets the read and write timeouts for the port to millisec milliseconds. +Setting 0 indicates that timeouts are not used for read nor write operations; +however read() and write() functions will still block. Set -1 to provide +non-blocking behaviour (read() and write() will return immediately). + +\note this function does nothing in event driven mode. +*/ +void QextSerialPort::setTimeout(long millisec) { + QMutexLocker lock(mutex); + Settings.Timeout_Millisec = millisec; + + if (millisec == -1) { + Win_CommTimeouts.ReadIntervalTimeout = MAXDWORD; + Win_CommTimeouts.ReadTotalTimeoutConstant = 0; + } else { + Win_CommTimeouts.ReadIntervalTimeout = millisec; + Win_CommTimeouts.ReadTotalTimeoutConstant = millisec; + } + Win_CommTimeouts.ReadTotalTimeoutMultiplier = 0; + Win_CommTimeouts.WriteTotalTimeoutMultiplier = millisec; + Win_CommTimeouts.WriteTotalTimeoutConstant = 0; + if (queryMode() != QextSerialPort::EventDriven) + SetCommTimeouts(Win_Handle, &Win_CommTimeouts); +} +