彻底改版2.0
This commit is contained in:
9
tool/3rd_qextserialport/3rd_qextserialport.pri
Normal file
9
tool/3rd_qextserialport/3rd_qextserialport.pri
Normal file
@@ -0,0 +1,9 @@
|
||||
HEADERS += \
|
||||
$$PWD/qextserialport.h \
|
||||
$$PWD/qextserialport_global.h \
|
||||
$$PWD/qextserialport_p.h
|
||||
|
||||
SOURCES += $$PWD/qextserialport.cpp
|
||||
|
||||
win32:SOURCES += $$PWD/qextserialport_win.cpp
|
||||
unix:SOURCES += $$PWD/qextserialport_unix.cpp
|
||||
1095
tool/3rd_qextserialport/qextserialport.cpp
Normal file
1095
tool/3rd_qextserialport/qextserialport.cpp
Normal file
File diff suppressed because it is too large
Load Diff
234
tool/3rd_qextserialport/qextserialport.h
Normal file
234
tool/3rd_qextserialport/qextserialport.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2000-2003 Wayne Roth
|
||||
** Copyright (c) 2004-2007 Stefan Sander
|
||||
** Copyright (c) 2007 Michal Policht
|
||||
** Copyright (c) 2008 Brandon Fosdick
|
||||
** Copyright (c) 2009-2010 Liam Staskawicz
|
||||
** Copyright (c) 2011 Debao Zhang
|
||||
** All right reserved.
|
||||
** Web: http://code.google.com/p/qextserialport/
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _QEXTSERIALPORT_H_
|
||||
#define _QEXTSERIALPORT_H_
|
||||
|
||||
#include <QtCore/QIODevice>
|
||||
#include "qextserialport_global.h"
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <termios.h>
|
||||
#endif
|
||||
/*line status constants*/
|
||||
// ### QESP2.0 move to enum
|
||||
#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*/
|
||||
// ### QESP2.0 move to enum
|
||||
#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
|
||||
#define E_PERMISSION_DENIED 16
|
||||
#define E_AGAIN 17
|
||||
|
||||
enum BaudRateType {
|
||||
#if defined(Q_OS_UNIX) || defined(qdoc)
|
||||
BAUD50 = 50, //POSIX ONLY
|
||||
BAUD75 = 75, //POSIX ONLY
|
||||
BAUD134 = 134, //POSIX ONLY
|
||||
BAUD150 = 150, //POSIX ONLY
|
||||
BAUD200 = 200, //POSIX ONLY
|
||||
BAUD1800 = 1800, //POSIX ONLY
|
||||
# if defined(B76800) || defined(qdoc)
|
||||
BAUD76800 = 76800, //POSIX ONLY
|
||||
# endif
|
||||
# if (defined(B230400) && defined(B4000000)) || defined(qdoc)
|
||||
BAUD230400 = 230400, //POSIX ONLY
|
||||
BAUD460800 = 460800, //POSIX ONLY
|
||||
BAUD500000 = 500000, //POSIX ONLY
|
||||
BAUD576000 = 576000, //POSIX ONLY
|
||||
BAUD921600 = 921600, //POSIX ONLY
|
||||
BAUD1000000 = 1000000, //POSIX ONLY
|
||||
BAUD1152000 = 1152000, //POSIX ONLY
|
||||
BAUD1500000 = 1500000, //POSIX ONLY
|
||||
BAUD2000000 = 2000000, //POSIX ONLY
|
||||
BAUD2500000 = 2500000, //POSIX ONLY
|
||||
BAUD3000000 = 3000000, //POSIX ONLY
|
||||
BAUD3500000 = 3500000, //POSIX ONLY
|
||||
BAUD4000000 = 4000000, //POSIX ONLY
|
||||
# endif
|
||||
#endif //Q_OS_UNIX
|
||||
#if defined(Q_OS_WIN) || defined(qdoc)
|
||||
BAUD14400 = 14400, //WINDOWS ONLY
|
||||
BAUD56000 = 56000, //WINDOWS ONLY
|
||||
BAUD128000 = 128000, //WINDOWS ONLY
|
||||
BAUD256000 = 256000, //WINDOWS ONLY
|
||||
#endif //Q_OS_WIN
|
||||
BAUD110 = 110,
|
||||
BAUD300 = 300,
|
||||
BAUD600 = 600,
|
||||
BAUD1200 = 1200,
|
||||
BAUD2400 = 2400,
|
||||
BAUD4800 = 4800,
|
||||
BAUD9600 = 9600,
|
||||
BAUD19200 = 19200,
|
||||
BAUD38400 = 38400,
|
||||
BAUD57600 = 57600,
|
||||
BAUD115200 = 115200
|
||||
};
|
||||
|
||||
enum DataBitsType {
|
||||
DATA_5 = 5,
|
||||
DATA_6 = 6,
|
||||
DATA_7 = 7,
|
||||
DATA_8 = 8
|
||||
};
|
||||
|
||||
enum ParityType {
|
||||
PAR_NONE,
|
||||
PAR_ODD,
|
||||
PAR_EVEN,
|
||||
#if defined(Q_OS_WIN) || defined(qdoc)
|
||||
PAR_MARK, //WINDOWS ONLY
|
||||
#endif
|
||||
PAR_SPACE
|
||||
};
|
||||
|
||||
enum StopBitsType {
|
||||
STOP_1,
|
||||
#if defined(Q_OS_WIN) || defined(qdoc)
|
||||
STOP_1_5, //WINDOWS ONLY
|
||||
#endif
|
||||
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;
|
||||
};
|
||||
|
||||
class QextSerialPortPrivate;
|
||||
class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(QextSerialPort)
|
||||
Q_ENUMS(QueryMode)
|
||||
Q_PROPERTY(QString portName READ portName WRITE setPortName)
|
||||
Q_PROPERTY(QueryMode queryMode READ queryMode WRITE setQueryMode)
|
||||
public:
|
||||
enum QueryMode {
|
||||
Polling,
|
||||
EventDriven
|
||||
};
|
||||
|
||||
explicit QextSerialPort(QueryMode mode = EventDriven, QObject *parent = 0);
|
||||
explicit QextSerialPort(const QString &name, QueryMode mode = EventDriven, QObject *parent = 0);
|
||||
explicit QextSerialPort(const PortSettings &s, QueryMode mode = EventDriven, QObject *parent = 0);
|
||||
QextSerialPort(const QString &name, const PortSettings &s, QueryMode mode = EventDriven, QObject *parent = 0);
|
||||
|
||||
~QextSerialPort();
|
||||
|
||||
QString portName() const;
|
||||
QueryMode queryMode() const;
|
||||
BaudRateType baudRate() const;
|
||||
DataBitsType dataBits() const;
|
||||
ParityType parity() const;
|
||||
StopBitsType stopBits() const;
|
||||
FlowType flowControl() const;
|
||||
|
||||
bool open(OpenMode mode);
|
||||
bool isSequential() const;
|
||||
void close();
|
||||
void flush();
|
||||
qint64 bytesAvailable() const;
|
||||
bool canReadLine() const;
|
||||
QByteArray readAll();
|
||||
|
||||
ulong lastError() const;
|
||||
|
||||
ulong lineStatus();
|
||||
QString errorString();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setPortName(const QString &name);
|
||||
void setQueryMode(QueryMode mode);
|
||||
void setBaudRate(BaudRateType);
|
||||
void setDataBits(DataBitsType);
|
||||
void setParity(ParityType);
|
||||
void setStopBits(StopBitsType);
|
||||
void setFlowControl(FlowType);
|
||||
void setTimeout(long);
|
||||
|
||||
void setDtr(bool set = true);
|
||||
void setRts(bool set = true);
|
||||
|
||||
Q_SIGNALS:
|
||||
void dsrChanged(bool status);
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxSize);
|
||||
qint64 writeData(const char *data, qint64 maxSize);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QextSerialPort)
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_onWinEvent(HANDLE))
|
||||
#endif
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_canRead())
|
||||
|
||||
QextSerialPortPrivate *const d_ptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
72
tool/3rd_qextserialport/qextserialport_global.h
Normal file
72
tool/3rd_qextserialport/qextserialport_global.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2000-2003 Wayne Roth
|
||||
** Copyright (c) 2004-2007 Stefan Sander
|
||||
** Copyright (c) 2007 Michal Policht
|
||||
** Copyright (c) 2008 Brandon Fosdick
|
||||
** Copyright (c) 2009-2010 Liam Staskawicz
|
||||
** Copyright (c) 2011 Debao Zhang
|
||||
** All right reserved.
|
||||
** Web: http://code.google.com/p/qextserialport/
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QEXTSERIALPORT_GLOBAL_H
|
||||
#define QEXTSERIALPORT_GLOBAL_H
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#ifdef QEXTSERIALPORT_BUILD_SHARED
|
||||
# define QEXTSERIALPORT_EXPORT Q_DECL_EXPORT
|
||||
#elif defined(QEXTSERIALPORT_USING_SHARED)
|
||||
# define QEXTSERIALPORT_EXPORT Q_DECL_IMPORT
|
||||
#else
|
||||
# define QEXTSERIALPORT_EXPORT
|
||||
#endif
|
||||
|
||||
// ### for compatible with old version. should be removed in QESP 2.0
|
||||
#ifdef _TTY_NOWARN_
|
||||
# define QESP_NO_WARN
|
||||
#endif
|
||||
#ifdef _TTY_NOWARN_PORT_
|
||||
# define QESP_NO_PORTABILITY_WARN
|
||||
#endif
|
||||
|
||||
/*if all warning messages are turned off, flag portability warnings to be turned off as well*/
|
||||
#ifdef QESP_NO_WARN
|
||||
# define QESP_NO_PORTABILITY_WARN
|
||||
#endif
|
||||
|
||||
/*macros for warning and debug messages*/
|
||||
#ifdef QESP_NO_PORTABILITY_WARN
|
||||
# define QESP_PORTABILITY_WARNING while (false)qWarning
|
||||
#else
|
||||
# define QESP_PORTABILITY_WARNING qWarning
|
||||
#endif /*QESP_NOWARN_PORT*/
|
||||
|
||||
#ifdef QESP_NO_WARN
|
||||
# define QESP_WARNING while (false)qWarning
|
||||
#else
|
||||
# define QESP_WARNING qWarning
|
||||
#endif /*QESP_NOWARN*/
|
||||
|
||||
#endif // QEXTSERIALPORT_GLOBAL_H
|
||||
|
||||
277
tool/3rd_qextserialport/qextserialport_p.h
Normal file
277
tool/3rd_qextserialport/qextserialport_p.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2000-2003 Wayne Roth
|
||||
** Copyright (c) 2004-2007 Stefan Sander
|
||||
** Copyright (c) 2007 Michal Policht
|
||||
** Copyright (c) 2008 Brandon Fosdick
|
||||
** Copyright (c) 2009-2010 Liam Staskawicz
|
||||
** Copyright (c) 2011 Debao Zhang
|
||||
** All right reserved.
|
||||
** Web: http://code.google.com/p/qextserialport/
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _QEXTSERIALPORT_P_H_
|
||||
#define _QEXTSERIALPORT_P_H_
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the QESP API. It exists for the convenience
|
||||
// of other QESP classes. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qextserialport.h"
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <termios.h>
|
||||
#elif (defined Q_OS_WIN)
|
||||
# include <QtCore/qt_windows.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
// This is QextSerialPort's read buffer, needed by posix system.
|
||||
// ref: QRingBuffer & QIODevicePrivateLinearBuffer
|
||||
class QextReadBuffer
|
||||
{
|
||||
public:
|
||||
inline QextReadBuffer(size_t growth = 4096)
|
||||
: len(0), first(0), buf(0), capacity(0), basicBlockSize(growth)
|
||||
{
|
||||
}
|
||||
|
||||
~QextReadBuffer()
|
||||
{
|
||||
delete buf;
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
first = buf;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
inline int size() const
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
inline bool isEmpty() const
|
||||
{
|
||||
return len == 0;
|
||||
}
|
||||
|
||||
inline int read(char *target, int size)
|
||||
{
|
||||
int r = qMin(size, len);
|
||||
|
||||
if (r == 1) {
|
||||
*target = *first;
|
||||
--len;
|
||||
++first;
|
||||
} else {
|
||||
memcpy(target, first, r);
|
||||
len -= r;
|
||||
first += r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline char *reserve(size_t size)
|
||||
{
|
||||
if ((first - buf) + len + size > capacity) {
|
||||
size_t newCapacity = qMax(capacity, basicBlockSize);
|
||||
|
||||
while (newCapacity < len + size) {
|
||||
newCapacity *= 2;
|
||||
}
|
||||
|
||||
if (newCapacity > capacity) {
|
||||
// allocate more space
|
||||
char *newBuf = new char[newCapacity];
|
||||
memmove(newBuf, first, len);
|
||||
delete buf;
|
||||
buf = newBuf;
|
||||
capacity = newCapacity;
|
||||
} else {
|
||||
// shift any existing data to make space
|
||||
memmove(buf, first, len);
|
||||
}
|
||||
|
||||
first = buf;
|
||||
}
|
||||
|
||||
char *writePtr = first + len;
|
||||
len += (int)size;
|
||||
return writePtr;
|
||||
}
|
||||
|
||||
inline void chop(int size)
|
||||
{
|
||||
if (size >= len) {
|
||||
clear();
|
||||
} else {
|
||||
len -= size;
|
||||
}
|
||||
}
|
||||
|
||||
inline void squeeze()
|
||||
{
|
||||
if (first != buf) {
|
||||
memmove(buf, first, len);
|
||||
first = buf;
|
||||
}
|
||||
|
||||
size_t newCapacity = basicBlockSize;
|
||||
|
||||
while (newCapacity < size_t(len)) {
|
||||
newCapacity *= 2;
|
||||
}
|
||||
|
||||
if (newCapacity < capacity) {
|
||||
char *tmp = static_cast<char *>(realloc(buf, newCapacity));
|
||||
|
||||
if (tmp) {
|
||||
buf = tmp;
|
||||
capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline QByteArray readAll()
|
||||
{
|
||||
char *f = first;
|
||||
int l = len;
|
||||
clear();
|
||||
return QByteArray(f, l);
|
||||
}
|
||||
|
||||
inline int readLine(char *target, int size)
|
||||
{
|
||||
int r = qMin(size, len);
|
||||
char *eol = static_cast<char *>(memchr(first, '\n', r));
|
||||
|
||||
if (eol) {
|
||||
r = 1 + (eol - first);
|
||||
}
|
||||
|
||||
memcpy(target, first, r);
|
||||
len -= r;
|
||||
first += r;
|
||||
return int(r);
|
||||
}
|
||||
|
||||
inline bool canReadLine() const
|
||||
{
|
||||
return memchr(first, '\n', len);
|
||||
}
|
||||
|
||||
private:
|
||||
int len;
|
||||
char *first;
|
||||
char *buf;
|
||||
size_t capacity;
|
||||
size_t basicBlockSize;
|
||||
};
|
||||
|
||||
class QWinEventNotifier;
|
||||
class QReadWriteLock;
|
||||
class QSocketNotifier;
|
||||
|
||||
class QextSerialPortPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QextSerialPort)
|
||||
public:
|
||||
QextSerialPortPrivate(QextSerialPort *q);
|
||||
~QextSerialPortPrivate();
|
||||
enum DirtyFlagEnum {
|
||||
DFE_BaudRate = 0x0001,
|
||||
DFE_Parity = 0x0002,
|
||||
DFE_StopBits = 0x0004,
|
||||
DFE_DataBits = 0x0008,
|
||||
DFE_Flow = 0x0010,
|
||||
DFE_TimeOut = 0x0100,
|
||||
DFE_ALL = 0x0fff,
|
||||
DFE_Settings_Mask = 0x00ff //without TimeOut
|
||||
};
|
||||
mutable QReadWriteLock lock;
|
||||
QString port;
|
||||
PortSettings settings;
|
||||
QextReadBuffer readBuffer;
|
||||
int settingsDirtyFlags;
|
||||
ulong lastErr;
|
||||
QextSerialPort::QueryMode queryMode;
|
||||
|
||||
// platform specific members
|
||||
#ifdef Q_OS_UNIX
|
||||
int fd;
|
||||
QSocketNotifier *readNotifier;
|
||||
struct termios currentTermios;
|
||||
struct termios oldTermios;
|
||||
#elif (defined Q_OS_WIN)
|
||||
HANDLE handle;
|
||||
OVERLAPPED overlap;
|
||||
COMMCONFIG commConfig;
|
||||
COMMTIMEOUTS commTimeouts;
|
||||
QWinEventNotifier *winEventNotifier;
|
||||
DWORD eventMask;
|
||||
QList<OVERLAPPED *> pendingWrites;
|
||||
QReadWriteLock *bytesToWriteLock;
|
||||
#endif
|
||||
|
||||
/*fill PortSettings*/
|
||||
void setBaudRate(BaudRateType baudRate, bool update = true);
|
||||
void setDataBits(DataBitsType dataBits, bool update = true);
|
||||
void setParity(ParityType parity, bool update = true);
|
||||
void setStopBits(StopBitsType stopbits, bool update = true);
|
||||
void setFlowControl(FlowType flow, bool update = true);
|
||||
void setTimeout(long millisec, bool update = true);
|
||||
void setPortSettings(const PortSettings &settings, bool update = true);
|
||||
|
||||
void platformSpecificDestruct();
|
||||
void platformSpecificInit();
|
||||
void translateError(ulong error);
|
||||
void updatePortSettings();
|
||||
|
||||
qint64 readData_sys(char *data, qint64 maxSize);
|
||||
qint64 writeData_sys(const char *data, qint64 maxSize);
|
||||
void setDtr_sys(bool set = true);
|
||||
void setRts_sys(bool set = true);
|
||||
bool open_sys(QIODevice::OpenMode mode);
|
||||
bool close_sys();
|
||||
bool flush_sys();
|
||||
ulong lineStatus_sys();
|
||||
qint64 bytesAvailable_sys() const;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
void _q_onWinEvent(HANDLE h);
|
||||
#endif
|
||||
void _q_canRead();
|
||||
|
||||
QextSerialPort *q_ptr;
|
||||
};
|
||||
|
||||
#endif //_QEXTSERIALPORT_P_H_
|
||||
559
tool/3rd_qextserialport/qextserialport_unix.cpp
Normal file
559
tool/3rd_qextserialport/qextserialport_unix.cpp
Normal file
@@ -0,0 +1,559 @@
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2000-2003 Wayne Roth
|
||||
** Copyright (c) 2004-2007 Stefan Sander
|
||||
** Copyright (c) 2007 Michal Policht
|
||||
** Copyright (c) 2008 Brandon Fosdick
|
||||
** Copyright (c) 2009-2010 Liam Staskawicz
|
||||
** Copyright (c) 2011 Debao Zhang
|
||||
** All right reserved.
|
||||
** Web: http://code.google.com/p/qextserialport/
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qextserialport.h"
|
||||
#include "qextserialport_p.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <QtCore/QMutexLocker>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QSocketNotifier>
|
||||
|
||||
void QextSerialPortPrivate::platformSpecificInit()
|
||||
{
|
||||
fd = 0;
|
||||
readNotifier = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Standard destructor.
|
||||
*/
|
||||
void QextSerialPortPrivate::platformSpecificDestruct()
|
||||
{
|
||||
}
|
||||
|
||||
static QString fullPortName(const QString &name)
|
||||
{
|
||||
if (name.startsWith(QLatin1Char('/'))) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return QLatin1String("/dev/") + name;
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
|
||||
{
|
||||
Q_Q(QextSerialPort);
|
||||
|
||||
//note: linux 2.6.21 seems to ignore O_NDELAY flag
|
||||
if ((fd = ::open(fullPortName(port).toLatin1() , O_RDWR | O_NOCTTY | O_NDELAY)) != -1) {
|
||||
|
||||
/*In the Private class, We can not call QIODevice::open()*/
|
||||
q->setOpenMode(mode); // Flag the port as opened
|
||||
::tcgetattr(fd, &oldTermios); // Save the old termios
|
||||
currentTermios = oldTermios; // Make a working copy
|
||||
::cfmakeraw(¤tTermios); // Enable raw access
|
||||
|
||||
/*set up other port settings*/
|
||||
currentTermios.c_cflag |= CREAD | CLOCAL;
|
||||
currentTermios.c_lflag &= (~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG));
|
||||
currentTermios.c_iflag &= (~(INPCK | IGNPAR | PARMRK | ISTRIP | ICRNL | IXANY));
|
||||
currentTermios.c_oflag &= (~OPOST);
|
||||
currentTermios.c_cc[VMIN] = 0;
|
||||
#ifdef _POSIX_VDISABLE // Is a disable character available on this system?
|
||||
// Some systems allow for per-device disable-characters, so get the
|
||||
// proper value for the configured device
|
||||
const long vdisable = ::fpathconf(fd, _PC_VDISABLE);
|
||||
currentTermios.c_cc[VINTR] = vdisable;
|
||||
currentTermios.c_cc[VQUIT] = vdisable;
|
||||
currentTermios.c_cc[VSTART] = vdisable;
|
||||
currentTermios.c_cc[VSTOP] = vdisable;
|
||||
currentTermios.c_cc[VSUSP] = vdisable;
|
||||
#endif //_POSIX_VDISABLE
|
||||
settingsDirtyFlags = DFE_ALL;
|
||||
updatePortSettings();
|
||||
|
||||
if (queryMode == QextSerialPort::EventDriven) {
|
||||
readNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q);
|
||||
q->connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_q_canRead()));
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
translateError(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::close_sys()
|
||||
{
|
||||
// Force a flush and then restore the original termios
|
||||
flush_sys();
|
||||
// Using both TCSAFLUSH and TCSANOW here discards any pending input
|
||||
::tcsetattr(fd, TCSAFLUSH | TCSANOW, &oldTermios); // Restore termios
|
||||
::close(fd);
|
||||
|
||||
if (readNotifier) {
|
||||
delete readNotifier;
|
||||
readNotifier = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::flush_sys()
|
||||
{
|
||||
::tcdrain(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 QextSerialPortPrivate::bytesAvailable_sys() const
|
||||
{
|
||||
int bytesQueued;
|
||||
|
||||
if (::ioctl(fd, FIONREAD, &bytesQueued) == -1) {
|
||||
return (qint64) - 1;
|
||||
}
|
||||
|
||||
return bytesQueued;
|
||||
}
|
||||
|
||||
/*!
|
||||
Translates a system-specific error code to a QextSerialPort error code. Used internally.
|
||||
*/
|
||||
void QextSerialPortPrivate::translateError(ulong error)
|
||||
{
|
||||
switch (error) {
|
||||
case EBADF:
|
||||
case ENOTTY:
|
||||
lastErr = E_INVALID_FD;
|
||||
break;
|
||||
|
||||
case EINTR:
|
||||
lastErr = E_CAUGHT_NON_BLOCKED_SIGNAL;
|
||||
break;
|
||||
|
||||
case ENOMEM:
|
||||
lastErr = E_NO_MEMORY;
|
||||
break;
|
||||
|
||||
case EACCES:
|
||||
lastErr = E_PERMISSION_DENIED;
|
||||
break;
|
||||
|
||||
case EAGAIN:
|
||||
lastErr = E_AGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::setDtr_sys(bool set)
|
||||
{
|
||||
int status;
|
||||
::ioctl(fd, TIOCMGET, &status);
|
||||
|
||||
if (set) {
|
||||
status |= TIOCM_DTR;
|
||||
} else {
|
||||
status &= ~TIOCM_DTR;
|
||||
}
|
||||
|
||||
::ioctl(fd, TIOCMSET, &status);
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::setRts_sys(bool set)
|
||||
{
|
||||
int status;
|
||||
::ioctl(fd, TIOCMGET, &status);
|
||||
|
||||
if (set) {
|
||||
status |= TIOCM_RTS;
|
||||
} else {
|
||||
status &= ~TIOCM_RTS;
|
||||
}
|
||||
|
||||
::ioctl(fd, TIOCMSET, &status);
|
||||
}
|
||||
|
||||
unsigned long QextSerialPortPrivate::lineStatus_sys()
|
||||
{
|
||||
unsigned long Status = 0, Temp = 0;
|
||||
::ioctl(fd, TIOCMGET, &Temp);
|
||||
|
||||
if (Temp & TIOCM_CTS) {
|
||||
Status |= LS_CTS;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_DSR) {
|
||||
Status |= LS_DSR;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_RI) {
|
||||
Status |= LS_RI;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_CD) {
|
||||
Status |= LS_DCD;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_DTR) {
|
||||
Status |= LS_DTR;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_RTS) {
|
||||
Status |= LS_RTS;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_ST) {
|
||||
Status |= LS_ST;
|
||||
}
|
||||
|
||||
if (Temp & TIOCM_SR) {
|
||||
Status |= LS_SR;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a block of data from the serial port. This function will read at most maxSize 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 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize)
|
||||
{
|
||||
int retVal = ::read(fd, data, maxSize);
|
||||
|
||||
if (retVal == -1) {
|
||||
lastErr = E_READ_FAILED;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*!
|
||||
Writes a block of data to the serial port. This function will write maxSize 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 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize)
|
||||
{
|
||||
int retVal = ::write(fd, data, maxSize);
|
||||
|
||||
if (retVal == -1) {
|
||||
lastErr = E_WRITE_FAILED;
|
||||
}
|
||||
|
||||
return (qint64)retVal;
|
||||
}
|
||||
|
||||
static void setBaudRate2Termios(termios *config, int baudRate)
|
||||
{
|
||||
#ifdef CBAUD
|
||||
config->c_cflag &= (~CBAUD);
|
||||
config->c_cflag |= baudRate;
|
||||
#else
|
||||
::cfsetispeed(config, baudRate);
|
||||
::cfsetospeed(config, baudRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
All the platform settings was performed in this function.
|
||||
*/
|
||||
void QextSerialPortPrivate::updatePortSettings()
|
||||
{
|
||||
if (!q_func()->isOpen() || !settingsDirtyFlags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_BaudRate) {
|
||||
switch (settings.BaudRate) {
|
||||
case BAUD50:
|
||||
setBaudRate2Termios(¤tTermios, B50);
|
||||
break;
|
||||
|
||||
case BAUD75:
|
||||
setBaudRate2Termios(¤tTermios, B75);
|
||||
break;
|
||||
|
||||
case BAUD110:
|
||||
setBaudRate2Termios(¤tTermios, B110);
|
||||
break;
|
||||
|
||||
case BAUD134:
|
||||
setBaudRate2Termios(¤tTermios, B134);
|
||||
break;
|
||||
|
||||
case BAUD150:
|
||||
setBaudRate2Termios(¤tTermios, B150);
|
||||
break;
|
||||
|
||||
case BAUD200:
|
||||
setBaudRate2Termios(¤tTermios, B200);
|
||||
break;
|
||||
|
||||
case BAUD300:
|
||||
setBaudRate2Termios(¤tTermios, B300);
|
||||
break;
|
||||
|
||||
case BAUD600:
|
||||
setBaudRate2Termios(¤tTermios, B600);
|
||||
break;
|
||||
|
||||
case BAUD1200:
|
||||
setBaudRate2Termios(¤tTermios, B1200);
|
||||
break;
|
||||
|
||||
case BAUD1800:
|
||||
setBaudRate2Termios(¤tTermios, B1800);
|
||||
break;
|
||||
|
||||
case BAUD2400:
|
||||
setBaudRate2Termios(¤tTermios, B2400);
|
||||
break;
|
||||
|
||||
case BAUD4800:
|
||||
setBaudRate2Termios(¤tTermios, B4800);
|
||||
break;
|
||||
|
||||
case BAUD9600:
|
||||
setBaudRate2Termios(¤tTermios, B9600);
|
||||
break;
|
||||
|
||||
case BAUD19200:
|
||||
setBaudRate2Termios(¤tTermios, B19200);
|
||||
break;
|
||||
|
||||
case BAUD38400:
|
||||
setBaudRate2Termios(¤tTermios, B38400);
|
||||
break;
|
||||
|
||||
case BAUD57600:
|
||||
setBaudRate2Termios(¤tTermios, B57600);
|
||||
break;
|
||||
#ifdef B76800
|
||||
|
||||
case BAUD76800:
|
||||
setBaudRate2Termios(¤tTermios, B76800);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case BAUD115200:
|
||||
setBaudRate2Termios(¤tTermios, B115200);
|
||||
break;
|
||||
#if defined(B230400) && defined(B4000000)
|
||||
|
||||
case BAUD230400:
|
||||
setBaudRate2Termios(¤tTermios, B230400);
|
||||
break;
|
||||
|
||||
case BAUD460800:
|
||||
setBaudRate2Termios(¤tTermios, B460800);
|
||||
break;
|
||||
|
||||
case BAUD500000:
|
||||
setBaudRate2Termios(¤tTermios, B500000);
|
||||
break;
|
||||
|
||||
case BAUD576000:
|
||||
setBaudRate2Termios(¤tTermios, B576000);
|
||||
break;
|
||||
|
||||
case BAUD921600:
|
||||
setBaudRate2Termios(¤tTermios, B921600);
|
||||
break;
|
||||
|
||||
case BAUD1000000:
|
||||
setBaudRate2Termios(¤tTermios, B1000000);
|
||||
break;
|
||||
|
||||
case BAUD1152000:
|
||||
setBaudRate2Termios(¤tTermios, B1152000);
|
||||
break;
|
||||
|
||||
case BAUD1500000:
|
||||
setBaudRate2Termios(¤tTermios, B1500000);
|
||||
break;
|
||||
|
||||
case BAUD2000000:
|
||||
setBaudRate2Termios(¤tTermios, B2000000);
|
||||
break;
|
||||
|
||||
case BAUD2500000:
|
||||
setBaudRate2Termios(¤tTermios, B2500000);
|
||||
break;
|
||||
|
||||
case BAUD3000000:
|
||||
setBaudRate2Termios(¤tTermios, B3000000);
|
||||
break;
|
||||
|
||||
case BAUD3500000:
|
||||
setBaudRate2Termios(¤tTermios, B3500000);
|
||||
break;
|
||||
|
||||
case BAUD4000000:
|
||||
setBaudRate2Termios(¤tTermios, B4000000);
|
||||
break;
|
||||
#endif
|
||||
#ifdef Q_OS_MAC
|
||||
|
||||
default:
|
||||
setBaudRate2Termios(¤tTermios, settings.BaudRate);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_Parity) {
|
||||
switch (settings.Parity) {
|
||||
case PAR_SPACE:
|
||||
/*space parity not directly supported - add an extra data bit to simulate it*/
|
||||
settingsDirtyFlags |= DFE_DataBits;
|
||||
break;
|
||||
|
||||
case PAR_NONE:
|
||||
currentTermios.c_cflag &= (~PARENB);
|
||||
break;
|
||||
|
||||
case PAR_EVEN:
|
||||
currentTermios.c_cflag &= (~PARODD);
|
||||
currentTermios.c_cflag |= PARENB;
|
||||
break;
|
||||
|
||||
case PAR_ODD:
|
||||
currentTermios.c_cflag |= (PARENB | PARODD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*must after Parity settings*/
|
||||
if (settingsDirtyFlags & DFE_DataBits) {
|
||||
if (settings.Parity != PAR_SPACE) {
|
||||
currentTermios.c_cflag &= (~CSIZE);
|
||||
|
||||
switch (settings.DataBits) {
|
||||
case DATA_5:
|
||||
currentTermios.c_cflag |= CS5;
|
||||
break;
|
||||
|
||||
case DATA_6:
|
||||
currentTermios.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case DATA_7:
|
||||
currentTermios.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case DATA_8:
|
||||
currentTermios.c_cflag |= CS8;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*space parity not directly supported - add an extra data bit to simulate it*/
|
||||
currentTermios.c_cflag &= ~(PARENB | CSIZE);
|
||||
|
||||
switch (settings.DataBits) {
|
||||
case DATA_5:
|
||||
currentTermios.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case DATA_6:
|
||||
currentTermios.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case DATA_7:
|
||||
currentTermios.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
case DATA_8:
|
||||
/*this will never happen, put here to Suppress an warning*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_StopBits) {
|
||||
switch (settings.StopBits) {
|
||||
case STOP_1:
|
||||
currentTermios.c_cflag &= (~CSTOPB);
|
||||
break;
|
||||
|
||||
case STOP_2:
|
||||
currentTermios.c_cflag |= CSTOPB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_Flow) {
|
||||
switch (settings.FlowControl) {
|
||||
case FLOW_OFF:
|
||||
currentTermios.c_cflag &= (~CRTSCTS);
|
||||
currentTermios.c_iflag &= (~(IXON | IXOFF | IXANY));
|
||||
break;
|
||||
|
||||
case FLOW_XONXOFF:
|
||||
/*software (XON/XOFF) flow control*/
|
||||
currentTermios.c_cflag &= (~CRTSCTS);
|
||||
currentTermios.c_iflag |= (IXON | IXOFF | IXANY);
|
||||
break;
|
||||
|
||||
case FLOW_HARDWARE:
|
||||
currentTermios.c_cflag |= CRTSCTS;
|
||||
currentTermios.c_iflag &= (~(IXON | IXOFF | IXANY));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*if any thing in currentTermios changed, flush*/
|
||||
if (settingsDirtyFlags & DFE_Settings_Mask) {
|
||||
::tcsetattr(fd, TCSAFLUSH, ¤tTermios);
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_TimeOut) {
|
||||
int millisec = settings.Timeout_Millisec;
|
||||
|
||||
if (millisec == -1) {
|
||||
::fcntl(fd, F_SETFL, O_NDELAY);
|
||||
} else {
|
||||
//O_SYNC should enable blocking ::write()
|
||||
//however this seems not working on Linux 2.6.21 (works on OpenBSD 4.2)
|
||||
::fcntl(fd, F_SETFL, O_SYNC);
|
||||
}
|
||||
|
||||
::tcgetattr(fd, ¤tTermios);
|
||||
currentTermios.c_cc[VTIME] = millisec / 100;
|
||||
::tcsetattr(fd, TCSAFLUSH, ¤tTermios);
|
||||
}
|
||||
|
||||
settingsDirtyFlags = 0;
|
||||
}
|
||||
482
tool/3rd_qextserialport/qextserialport_win.cpp
Normal file
482
tool/3rd_qextserialport/qextserialport_win.cpp
Normal file
@@ -0,0 +1,482 @@
|
||||
/****************************************************************************
|
||||
** Copyright (c) 2000-2003 Wayne Roth
|
||||
** Copyright (c) 2004-2007 Stefan Sander
|
||||
** Copyright (c) 2007 Michal Policht
|
||||
** Copyright (c) 2008 Brandon Fosdick
|
||||
** Copyright (c) 2009-2010 Liam Staskawicz
|
||||
** Copyright (c) 2011 Debao Zhang
|
||||
** All right reserved.
|
||||
** Web: http://code.google.com/p/qextserialport/
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
** "Software"), to deal in the Software without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Software, and to
|
||||
** permit persons to whom the Software is furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be
|
||||
** included in all copies or substantial portions of the Software.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qextserialport.h"
|
||||
#include "qextserialport_p.h"
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#include <QtCore/QMutexLocker>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtCore/QWinEventNotifier>
|
||||
#else
|
||||
#include <QtCore/private/qwineventnotifier_p.h>
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QtCore5Compat/QRegExp>
|
||||
#else
|
||||
#include <QtCore/QRegExp>
|
||||
#endif
|
||||
|
||||
void QextSerialPortPrivate::platformSpecificInit()
|
||||
{
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
ZeroMemory(&overlap, sizeof(OVERLAPPED));
|
||||
overlap.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
winEventNotifier = 0;
|
||||
bytesToWriteLock = new QReadWriteLock;
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::platformSpecificDestruct()
|
||||
{
|
||||
CloseHandle(overlap.hEvent);
|
||||
delete bytesToWriteLock;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\internal
|
||||
COM ports greater than 9 need \\.\ prepended
|
||||
|
||||
This is only need when open the port.
|
||||
*/
|
||||
static QString fullPortNameWin(const QString &name)
|
||||
{
|
||||
QRegExp rx(QLatin1String("^COM(\\d+)"));
|
||||
QString fullName(name);
|
||||
if (rx.indexIn(fullName) >= 0) {
|
||||
fullName.prepend(QLatin1String("\\\\.\\"));
|
||||
}
|
||||
|
||||
return fullName;
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::open_sys(QIODevice::OpenMode mode)
|
||||
{
|
||||
Q_Q(QextSerialPort);
|
||||
DWORD confSize = sizeof(COMMCONFIG);
|
||||
commConfig.dwSize = confSize;
|
||||
DWORD dwFlagsAndAttributes = 0;
|
||||
|
||||
if (queryMode == QextSerialPort::EventDriven) {
|
||||
dwFlagsAndAttributes += FILE_FLAG_OVERLAPPED;
|
||||
}
|
||||
|
||||
/*open the port*/
|
||||
handle = CreateFileW((wchar_t *)fullPortNameWin(port).utf16(), GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL);
|
||||
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
q->setOpenMode(mode);
|
||||
/*configure port settings*/
|
||||
GetCommConfig(handle, &commConfig, &confSize);
|
||||
GetCommState(handle, &(commConfig.dcb));
|
||||
|
||||
/*set up parameters*/
|
||||
commConfig.dcb.fBinary = TRUE;
|
||||
commConfig.dcb.fInX = FALSE;
|
||||
commConfig.dcb.fOutX = FALSE;
|
||||
commConfig.dcb.fAbortOnError = FALSE;
|
||||
commConfig.dcb.fNull = FALSE;
|
||||
/* Dtr default to true. See Issue 122*/
|
||||
commConfig.dcb.fDtrControl = TRUE;
|
||||
/*flush all settings*/
|
||||
settingsDirtyFlags = DFE_ALL;
|
||||
updatePortSettings();
|
||||
|
||||
//init event driven approach
|
||||
if (queryMode == QextSerialPort::EventDriven) {
|
||||
if (!SetCommMask(handle, EV_TXEMPTY | EV_RXCHAR | EV_DSR)) {
|
||||
QESP_WARNING() << "failed to set Comm Mask. Error code:" << GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
winEventNotifier = new QWinEventNotifier(overlap.hEvent, q);
|
||||
qRegisterMetaType<HANDLE>("HANDLE");
|
||||
q->connect(winEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onWinEvent(HANDLE)), Qt::DirectConnection);
|
||||
WaitCommEvent(handle, &eventMask, &overlap);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::close_sys()
|
||||
{
|
||||
flush_sys();
|
||||
CancelIo(handle);
|
||||
|
||||
if (CloseHandle(handle)) {
|
||||
handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (winEventNotifier) {
|
||||
winEventNotifier->setEnabled(false);
|
||||
winEventNotifier->deleteLater();
|
||||
winEventNotifier = 0;
|
||||
}
|
||||
|
||||
foreach (OVERLAPPED *o, pendingWrites) {
|
||||
CloseHandle(o->hEvent);
|
||||
delete o;
|
||||
}
|
||||
|
||||
pendingWrites.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QextSerialPortPrivate::flush_sys()
|
||||
{
|
||||
FlushFileBuffers(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
qint64 QextSerialPortPrivate::bytesAvailable_sys() const
|
||||
{
|
||||
DWORD Errors;
|
||||
COMSTAT Status;
|
||||
|
||||
if (ClearCommError(handle, &Errors, &Status)) {
|
||||
return Status.cbInQue;
|
||||
}
|
||||
|
||||
return (qint64) - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Translates a system-specific error code to a QextSerialPort error code. Used internally.
|
||||
*/
|
||||
void QextSerialPortPrivate::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 QextSerialPortPrivate::readData_sys(char *data, qint64 maxSize)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
bool failed = false;
|
||||
|
||||
if (queryMode == QextSerialPort::EventDriven) {
|
||||
OVERLAPPED overlapRead;
|
||||
ZeroMemory(&overlapRead, sizeof(OVERLAPPED));
|
||||
|
||||
if (!ReadFile(handle, (void *)data, (DWORD)maxSize, &bytesRead, &overlapRead)) {
|
||||
if (GetLastError() == ERROR_IO_PENDING) {
|
||||
GetOverlappedResult(handle, &overlapRead, &bytesRead, true);
|
||||
} else {
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
} else if (!ReadFile(handle, (void *)data, (DWORD)maxSize, &bytesRead, NULL)) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
return (qint64)bytesRead;
|
||||
}
|
||||
|
||||
lastErr = E_READ_FAILED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
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 QextSerialPortPrivate::writeData_sys(const char *data, qint64 maxSize)
|
||||
{
|
||||
DWORD bytesWritten = 0;
|
||||
bool failed = false;
|
||||
|
||||
if (queryMode == QextSerialPort::EventDriven) {
|
||||
OVERLAPPED *newOverlapWrite = new OVERLAPPED;
|
||||
ZeroMemory(newOverlapWrite, sizeof(OVERLAPPED));
|
||||
newOverlapWrite->hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
|
||||
if (WriteFile(handle, (void *)data, (DWORD)maxSize, &bytesWritten, newOverlapWrite)) {
|
||||
CloseHandle(newOverlapWrite->hEvent);
|
||||
delete newOverlapWrite;
|
||||
} else if (GetLastError() == ERROR_IO_PENDING) {
|
||||
// writing asynchronously...not an error
|
||||
QWriteLocker writelocker(bytesToWriteLock);
|
||||
pendingWrites.append(newOverlapWrite);
|
||||
} else {
|
||||
QESP_WARNING() << "QextSerialPort write error:" << GetLastError();
|
||||
failed = true;
|
||||
|
||||
if (!CancelIo(newOverlapWrite->hEvent)) {
|
||||
QESP_WARNING("QextSerialPort: couldn't cancel IO");
|
||||
}
|
||||
|
||||
if (!CloseHandle(newOverlapWrite->hEvent)) {
|
||||
QESP_WARNING("QextSerialPort: couldn't close OVERLAPPED handle");
|
||||
}
|
||||
|
||||
delete newOverlapWrite;
|
||||
}
|
||||
} else if (!WriteFile(handle, (void *)data, (DWORD)maxSize, &bytesWritten, NULL)) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
if (!failed) {
|
||||
return (qint64)bytesWritten;
|
||||
}
|
||||
|
||||
lastErr = E_WRITE_FAILED;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::setDtr_sys(bool set)
|
||||
{
|
||||
EscapeCommFunction(handle, set ? SETDTR : CLRDTR);
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::setRts_sys(bool set)
|
||||
{
|
||||
EscapeCommFunction(handle, set ? SETRTS : CLRRTS);
|
||||
}
|
||||
|
||||
ulong QextSerialPortPrivate::lineStatus_sys(void)
|
||||
{
|
||||
unsigned long Status = 0, Temp = 0;
|
||||
GetCommModemStatus(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;
|
||||
}
|
||||
|
||||
/*
|
||||
Triggered when there's activity on our HANDLE.
|
||||
*/
|
||||
void QextSerialPortPrivate::_q_onWinEvent(HANDLE h)
|
||||
{
|
||||
Q_Q(QextSerialPort);
|
||||
|
||||
if (h == overlap.hEvent) {
|
||||
if (eventMask & EV_RXCHAR) {
|
||||
if (q->sender() != q && bytesAvailable_sys() > 0) {
|
||||
_q_canRead();
|
||||
}
|
||||
}
|
||||
|
||||
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<OVERLAPPED *> overlapsToDelete;
|
||||
|
||||
foreach (OVERLAPPED *o, pendingWrites) {
|
||||
DWORD numBytes = 0;
|
||||
|
||||
if (GetOverlappedResult(handle, o, &numBytes, false)) {
|
||||
overlapsToDelete.append(o);
|
||||
totalBytesWritten += numBytes;
|
||||
} else if (GetLastError() != ERROR_IO_INCOMPLETE) {
|
||||
overlapsToDelete.append(o);
|
||||
QESP_WARNING() << "CommEvent overlapped write error:" << GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
if (q->sender() != q && totalBytesWritten > 0) {
|
||||
QWriteLocker writelocker(bytesToWriteLock);
|
||||
Q_EMIT q->bytesWritten(totalBytesWritten);
|
||||
}
|
||||
|
||||
foreach (OVERLAPPED *o, overlapsToDelete) {
|
||||
OVERLAPPED *toDelete = pendingWrites.takeAt(pendingWrites.indexOf(o));
|
||||
CloseHandle(toDelete->hEvent);
|
||||
delete toDelete;
|
||||
}
|
||||
}
|
||||
|
||||
if (eventMask & EV_DSR) {
|
||||
if (lineStatus_sys() & LS_DSR) {
|
||||
Q_EMIT q->dsrChanged(true);
|
||||
} else {
|
||||
Q_EMIT q->dsrChanged(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WaitCommEvent(handle, &eventMask, &overlap);
|
||||
}
|
||||
|
||||
void QextSerialPortPrivate::updatePortSettings()
|
||||
{
|
||||
if (!q_ptr->isOpen() || !settingsDirtyFlags) {
|
||||
return;
|
||||
}
|
||||
|
||||
//fill struct : COMMCONFIG
|
||||
if (settingsDirtyFlags & DFE_BaudRate) {
|
||||
commConfig.dcb.BaudRate = settings.BaudRate;
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_Parity) {
|
||||
commConfig.dcb.Parity = (BYTE)settings.Parity;
|
||||
commConfig.dcb.fParity = (settings.Parity == PAR_NONE) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_DataBits) {
|
||||
commConfig.dcb.ByteSize = (BYTE)settings.DataBits;
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_StopBits) {
|
||||
switch (settings.StopBits) {
|
||||
case STOP_1:
|
||||
commConfig.dcb.StopBits = ONESTOPBIT;
|
||||
break;
|
||||
|
||||
case STOP_1_5:
|
||||
commConfig.dcb.StopBits = ONE5STOPBITS;
|
||||
break;
|
||||
|
||||
case STOP_2:
|
||||
commConfig.dcb.StopBits = TWOSTOPBITS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsDirtyFlags & DFE_Flow) {
|
||||
switch (settings.FlowControl) {
|
||||
/*no flow control*/
|
||||
case FLOW_OFF:
|
||||
commConfig.dcb.fOutxCtsFlow = FALSE;
|
||||
commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
commConfig.dcb.fInX = FALSE;
|
||||
commConfig.dcb.fOutX = FALSE;
|
||||
break;
|
||||
|
||||
/*software (XON/XOFF) flow control*/
|
||||
case FLOW_XONXOFF:
|
||||
commConfig.dcb.fOutxCtsFlow = FALSE;
|
||||
commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
commConfig.dcb.fInX = TRUE;
|
||||
commConfig.dcb.fOutX = TRUE;
|
||||
break;
|
||||
|
||||
/*hardware flow control*/
|
||||
case FLOW_HARDWARE:
|
||||
commConfig.dcb.fOutxCtsFlow = TRUE;
|
||||
commConfig.dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
||||
commConfig.dcb.fInX = FALSE;
|
||||
commConfig.dcb.fOutX = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//fill struct : COMMTIMEOUTS
|
||||
if (settingsDirtyFlags & DFE_TimeOut) {
|
||||
if (queryMode != QextSerialPort::EventDriven) {
|
||||
int millisec = settings.Timeout_Millisec;
|
||||
|
||||
if (millisec == -1) {
|
||||
commTimeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
commTimeouts.ReadTotalTimeoutConstant = 0;
|
||||
} else {
|
||||
commTimeouts.ReadIntervalTimeout = millisec;
|
||||
commTimeouts.ReadTotalTimeoutConstant = millisec;
|
||||
}
|
||||
|
||||
commTimeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
commTimeouts.WriteTotalTimeoutMultiplier = millisec;
|
||||
commTimeouts.WriteTotalTimeoutConstant = 0;
|
||||
} else {
|
||||
commTimeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
commTimeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
commTimeouts.ReadTotalTimeoutConstant = 0;
|
||||
commTimeouts.WriteTotalTimeoutMultiplier = 0;
|
||||
commTimeouts.WriteTotalTimeoutConstant = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (settingsDirtyFlags & DFE_Settings_Mask) {
|
||||
SetCommConfig(handle, &commConfig, sizeof(COMMCONFIG));
|
||||
}
|
||||
|
||||
if ((settingsDirtyFlags & DFE_TimeOut)) {
|
||||
SetCommTimeouts(handle, &commTimeouts);
|
||||
}
|
||||
|
||||
settingsDirtyFlags = 0;
|
||||
}
|
||||
Reference in New Issue
Block a user