通用串口库加入

qt6
zcy 2021-04-02 00:46:23 +08:00
parent 2e9a1b69db
commit c5e5f10f87
19 changed files with 3720 additions and 25 deletions

24
Qss.cpp
View File

@ -103,6 +103,8 @@ QssTtitleBar::QssTtitleBar(QWidget *parent ,
QssTtitleBar::~QssTtitleBar() QssTtitleBar::~QssTtitleBar()
{ {
delete(this->m_maxBtn);
delete(this->m_restoreBtn);
} }
void QssTtitleBar::setTitle( QString title ) void QssTtitleBar::setTitle( QString title )
@ -118,7 +120,6 @@ void QssTtitleBar::setIcon( QIcon icon)
void QssTtitleBar::setMaxOrRestore( bool val) void QssTtitleBar::setMaxOrRestore( bool val)
{ {
m_maxOrRestore = val;//true m_maxOrRestore = val;//true
if ((m_type & QTitleBar_Button_Restore) && (m_type & QTitleBar_Button_Max)) if ((m_type & QTitleBar_Button_Restore) && (m_type & QTitleBar_Button_Max))
{ {
m_restoreBtn->setVisible(m_maxOrRestore); m_restoreBtn->setVisible(m_maxOrRestore);
@ -187,11 +188,6 @@ bool QssTtitleBar::eventFilter( QObject * obj, QEvent * ev )
return true; return true;
} }
} }
else if (obj == m_iconBtn)
{
}
return QWidget::eventFilter(obj, ev); return QWidget::eventFilter(obj, ev);
} }
@ -253,9 +249,7 @@ QssMainWindow::QssMainWindow(QWidget *parent/* = 0*/, Qt::WindowFlags flags/* =
m_bLeftPress(false) m_bLeftPress(false)
{ {
m_rcValid = QApplication::desktop()->availableGeometry(); m_rcValid = QApplication::desktop()->availableGeometry();
m_frame = new QFrame(parent, flags); m_frame = new QFrame(parent, flags);
//css
m_frame->setObjectName("window"); m_frame->setObjectName("window");
m_frame->setWindowFlags(Qt::Window | m_frame->setWindowFlags(Qt::Window |
@ -287,8 +281,6 @@ QssMainWindow::QssMainWindow(QWidget *parent/* = 0*/, Qt::WindowFlags flags/* =
QTextStream in(&file); QTextStream in(&file);
QString css = in.readAll(); QString css = in.readAll();
//this->setStyleSheet(css); //this->setStyleSheet(css);
return; return;
} }
@ -639,9 +631,12 @@ void QssMainWindow::ScaleChanged(float scale)
WId QssMainWindow::GetWID() const WId QssMainWindow::GetWID() const
{ {
return 0;
} }
void QssMainWindow::SetScale(float scale) void QssMainWindow::SetScale(float scale)
{ {
@ -649,8 +644,8 @@ void QssMainWindow::SetScale(float scale)
QssDialog::QssDialog(QWidget *parent) QssDialog::QssDialog(QWidget *parent)
: QDialog(0), : QDialog(0),
m_mousePressedInBorder(false), m_parent(parent),
m_parent(parent) m_mousePressedInBorder(false)
{ {
m_rcValid = QApplication::desktop()->availableGeometry(); m_rcValid = QApplication::desktop()->availableGeometry();
@ -696,13 +691,11 @@ void QssDockWidget::paintEvent(QPaintEvent *){
void QssDockWidget::show() void QssDockWidget::show()
{ {
/** resize m_framem_framesizehint */
int offset = (QSSDIALOG_SHADOW_WIDTH + QSSDIALOG_BODER_WIDTH)*2;//rect()<29><><EFBFBD><EFBFBD>padding<6E><67>paddingframe int offset = (QSSDIALOG_SHADOW_WIDTH + QSSDIALOG_BODER_WIDTH)*2;//rect()<29><><EFBFBD><EFBFBD>padding<6E><67>paddingframe
m_frame->resize(rect().width() + offset, rect().height() + m_titleBar->rect().height() + offset); m_frame->resize(rect().width() + offset, rect().height() + m_titleBar->rect().height() + offset);
QDockWidget::show(); QDockWidget::show();
m_frame->show(); m_frame->show();
//m_titleBar->show();
} }
void QssDialog::raise() void QssDialog::raise()
@ -722,7 +715,6 @@ int QssDialog::exec()
m_frame->resize(rect().width() + offset, rect().height() + m_titleBar->rect().height() + offset); m_frame->resize(rect().width() + offset, rect().height() + m_titleBar->rect().height() + offset);
m_frame->setWindowModality(Qt::ApplicationModal);//Qt::ApplicationModal m_frame->setWindowModality(Qt::ApplicationModal);//Qt::ApplicationModal
//m_frame->setWindowFlags(m_frame->windowFlags() | Qt::Tool);//Qt::Tool
m_frame->show(); m_frame->show();
m_frame->raise(); m_frame->raise();
@ -884,13 +876,11 @@ void QssDockWidget::onMousePressEvent( QMouseEvent * ev )
void QssDialog::onMouseReleaseEvent( QMouseEvent * ) void QssDialog::onMouseReleaseEvent( QMouseEvent * )
{ {
m_mousePressedInBorder = false; m_mousePressedInBorder = false;
//qDebug() << "mousePressed release in border";
} }
void QssDockWidget::onMouseReleaseEvent( QMouseEvent * ev ) void QssDockWidget::onMouseReleaseEvent( QMouseEvent * ev )
{ {
m_mousePressedInBorder = false; m_mousePressedInBorder = false;
//qDebug() << "mousePressed release in border";
} }
bool QssDialog::eventFilter( QObject * obj, QEvent * ev ) bool QssDialog::eventFilter( QObject * obj, QEvent * ev )

7
Qss.h
View File

@ -187,7 +187,7 @@ class QssEventFilter
{ {
public: public:
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE
{ {/*
MSG* pMsg = reinterpret_cast<MSG*>(message); MSG* pMsg = reinterpret_cast<MSG*>(message);
if(nullptr != pMsg){ if(nullptr != pMsg){
switch (pMsg->message) switch (pMsg->message)
@ -198,7 +198,7 @@ public:
} }
} }
} }*/
// TODO: filter out or modify msg struct here // TODO: filter out or modify msg struct here
return false; return false;
} }
@ -292,11 +292,12 @@ private:
void onMouseReleaseEvent(QMouseEvent * ev); void onMouseReleaseEvent(QMouseEvent * ev);
private: private:
QWidget* m_parent;
QFrame* m_frame; QFrame* m_frame;
QssTtitleBar* m_titleBar; QssTtitleBar* m_titleBar;
QRect m_rcValid; QRect m_rcValid;
QWidget* m_parent;
/** 边框调整大小相关 */ /** 边框调整大小相关 */
QRect mFrameRect; QRect mFrameRect;

View File

@ -44,6 +44,7 @@ QWidget#qssTitleBar >QPushButton#titlebarrestorebtn{
width: 40px; width: 40px;
height:30px; height:30px;
margin-left: 1px; margin-left: 1px;
margin-right: 2px;
} }
QWidget#qssTitleBar >QPushButton#titlebarrestorebtn:enabled:hover{ QWidget#qssTitleBar >QPushButton#titlebarrestorebtn:enabled:hover{
background: rgb(187, 212, 238); background: rgb(187, 212, 238);

View File

@ -0,0 +1,163 @@
/****************************************************************************
** 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 "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <QtCore/QMetaType>
#include <QtCore/QRegExp>
QextSerialEnumeratorPrivate::QextSerialEnumeratorPrivate(QextSerialEnumerator *enumrator)
:q_ptr(enumrator)
{
init_sys();
}
QextSerialEnumeratorPrivate::~QextSerialEnumeratorPrivate()
{
destroy_sys();
}
/*!
\class QextPortInfo
\brief The QextPortInfo class containing port information.
Structure containing port information.
\code
QString portName; ///< Port name.
QString physName; ///< Physical name.
QString friendName; ///< Friendly name.
QString enumName; ///< Enumerator name.
int vendorID; ///< Vendor ID.
int productID; ///< Product ID
\endcode
*/
/*! \class QextSerialEnumerator
\brief The QextSerialEnumerator class provides list of ports available in the system.
\section1 Usage
To poll the system for a list of connected devices, simply use getPorts(). Each
QextPortInfo structure will populated with information about the corresponding device.
\bold Example
\code
QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
foreach (QextPortInfo port, ports) {
// inspect port...
}
\endcode
To enable event-driven notification of device connection events, first call
setUpNotifications() and then connect to the deviceDiscovered() and deviceRemoved()
signals. Event-driven behavior is currently available only on Windows and OS X.
\bold Example
\code
QextSerialEnumerator *enumerator = new QextSerialEnumerator();
connect(enumerator, SIGNAL(deviceDiscovered(const QextPortInfo &)),
myClass, SLOT(onDeviceDiscovered(const QextPortInfo &)));
connect(enumerator, SIGNAL(deviceRemoved(const QextPortInfo &)),
myClass, SLOT(onDeviceRemoved(const QextPortInfo &)));
\endcode
\section1 Credits
Windows implementation is based on Zach Gorman's work from
\l {http://www.codeproject.com}{The Code Project} (\l http://www.codeproject.com/system/setupdi.asp).
OS X implementation, see \l http://developer.apple.com/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Finding_Devices/chapter_4_section_2.html
\bold author Michal Policht, Liam Staskawicz
*/
/*!
\fn void QextSerialEnumerator::deviceDiscovered(const QextPortInfo &info)
A new device has been connected to the system.
setUpNotifications() must be called first to enable event-driven device notifications.
Currently only implemented on Windows and OS X.
\a info The device that has been discovered.
*/
/*!
\fn void QextSerialEnumerator::deviceRemoved(const QextPortInfo &info);
A device has been disconnected from the system.
setUpNotifications() must be called first to enable event-driven device notifications.
Currently only implemented on Windows and OS X.
\a info The device that was disconnected.
*/
/*!
Constructs a QextSerialEnumerator object with the given \a parent.
*/
QextSerialEnumerator::QextSerialEnumerator(QObject *parent)
:QObject(parent), d_ptr(new QextSerialEnumeratorPrivate(this))
{
if (!QMetaType::isRegistered(QMetaType::type("QextPortInfo")))
qRegisterMetaType<QextPortInfo>("QextPortInfo");
}
/*!
Destructs the QextSerialEnumerator object.
*/
QextSerialEnumerator::~QextSerialEnumerator()
{
delete d_ptr;
}
/*!
Get list of ports.
return list of ports currently available in the system.
*/
QList<QextPortInfo> QextSerialEnumerator::getPorts()
{
return QextSerialEnumeratorPrivate::getPorts_sys();
}
/*!
Enable event-driven notifications of board discovery/removal.
*/
void QextSerialEnumerator::setUpNotifications()
{
Q_D(QextSerialEnumerator);
if (!d->setUpNotifications_sys(true))
QESP_WARNING("Setup Notification Failed...");
}
#include "moc_qextserialenumerator.cpp"

View 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 _QEXTSERIALENUMERATOR_H_
#define _QEXTSERIALENUMERATOR_H_
#include <QtCore/QList>
#include <QtCore/QObject>
#include "qextserialport_global.h"
struct QextPortInfo {
QString portName; ///< Port name.
QString physName; ///< Physical name.
QString friendName; ///< Friendly name.
QString enumName; ///< Enumerator name.
int vendorID; ///< Vendor ID.
int productID; ///< Product ID
};
class QextSerialEnumeratorPrivate;
class QEXTSERIALPORT_EXPORT QextSerialEnumerator : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QextSerialEnumerator)
public:
QextSerialEnumerator(QObject *parent=0);
~QextSerialEnumerator();
static QList<QextPortInfo> getPorts();
void setUpNotifications();
Q_SIGNALS:
void deviceDiscovered(const QextPortInfo &info);
void deviceRemoved(const QextPortInfo &info);
private:
Q_DISABLE_COPY(QextSerialEnumerator)
#if defined(Q_OS_LINUX) && !defined(QESP_NO_UDEV)
Q_PRIVATE_SLOT(d_func(), void _q_deviceEvent())
#endif
QextSerialEnumeratorPrivate *d_ptr;
};
#endif /*_QEXTSERIALENUMERATOR_H_*/

View File

@ -0,0 +1,210 @@
/****************************************************************************
** 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
** Copyright (c) 2012 Doug Brown
** 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 "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QDir>
void QextSerialEnumeratorPrivate::init_sys()
{
#ifndef QESP_NO_UDEV
monitor = NULL;
notifierFd = -1;
notifier = NULL;
udev = udev_new();
if (!udev)
qCritical() << "Unable to initialize udev notifications";
#endif
}
void QextSerialEnumeratorPrivate::destroy_sys()
{
#ifndef QESP_NO_UDEV
if (notifier) {
notifier->setEnabled(false);
delete notifier;
}
if (monitor)
udev_monitor_unref(monitor);
if (udev)
udev_unref(udev);
#endif
}
#ifndef QESP_NO_UDEV
static QextPortInfo portInfoFromDevice(struct udev_device *dev)
{
QString vendor = QString::fromLatin1(udev_device_get_property_value(dev, "ID_VENDOR_ID"));
QString product = QString::fromLatin1(udev_device_get_property_value(dev, "ID_MODEL_ID"));
QextPortInfo pi;
pi.vendorID = vendor.toInt(0, 16);
pi.productID = product.toInt(0, 16);
pi.portName = QString::fromLatin1(udev_device_get_devnode(dev));
pi.physName = pi.portName;
return pi;
}
#endif
QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
QList<QextPortInfo> infoList;
#ifndef QESP_NO_UDEV
struct udev *ud = udev_new();
if (!ud) {
qCritical() << "Unable to enumerate ports because udev is not initialized.";
return infoList;
}
struct udev_enumerate *enumerate = udev_enumerate_new(ud);
udev_enumerate_add_match_subsystem(enumerate, "tty");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry *list = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry *entry;
udev_list_entry_foreach(entry, list) {
const char *path;
struct udev_device *dev;
// Have to grab the actual udev device here...
path = udev_list_entry_get_name(entry);
dev = udev_device_new_from_syspath(ud, path);
infoList.append(portInfoFromDevice(dev));
// Done with this device
udev_device_unref(dev);
}
// Done with the list and this udev
udev_enumerate_unref(enumerate);
udev_unref(ud);
#else
QStringList portNamePrefixes, portNameList;
portNamePrefixes << QLatin1String("ttyS*"); // list normal serial ports first
QDir dir(QLatin1String("/dev"));
portNameList = dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);
// remove the values which are not serial ports for e.g. /dev/ttysa
for (int i = 0; i < portNameList.size(); i++) {
bool ok;
QString current = portNameList.at(i);
// remove the ttyS part, and check, if the other part is a number
current.remove(0,4).toInt(&ok, 10);
if (!ok) {
portNameList.removeAt(i);
i--;
}
}
// get the non standard serial ports names
// (USB-serial, bluetooth-serial, 18F PICs, and so on)
// if you know an other name prefix for serial ports please let us know
portNamePrefixes.clear();
portNamePrefixes << QLatin1String("ttyACM*") << QLatin1String("ttyUSB*") << QLatin1String("rfcomm*");
portNameList += dir.entryList(portNamePrefixes, (QDir::System | QDir::Files), QDir::Name);
foreach (QString str , portNameList) {
QextPortInfo inf;
inf.physName = QLatin1String("/dev/")+str;
inf.portName = str;
if (str.contains(QLatin1String("ttyS"))) {
inf.friendName = QLatin1String("Serial port ")+str.remove(0, 4);
}
else if (str.contains(QLatin1String("ttyUSB"))) {
inf.friendName = QLatin1String("USB-serial adapter ")+str.remove(0, 6);
}
else if (str.contains(QLatin1String("rfcomm"))) {
inf.friendName = QLatin1String("Bluetooth-serial adapter ")+str.remove(0, 6);
}
inf.enumName = QLatin1String("/dev"); // is there a more helpful name for this?
infoList.append(inf);
}
#endif
return infoList;
}
bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
{
Q_UNUSED(setup);
#ifndef QESP_NO_UDEV
Q_Q(QextSerialEnumerator);
if (!udev) {
qCritical() << "Unable to initialize notifications because udev is not initialized.";
return false;
}
// Emit signals immediately for devices already connected (Windows version seems to behave
// this way)
foreach (QextPortInfo i, getPorts_sys())
Q_EMIT q->deviceDiscovered(i);
// Look for tty devices from udev.
monitor = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(monitor, "tty", NULL);
udev_monitor_enable_receiving(monitor);
notifierFd = udev_monitor_get_fd(monitor);
notifier = new QSocketNotifier(notifierFd, QSocketNotifier::Read);
q->connect(notifier, SIGNAL(activated(int)), q, SLOT(_q_deviceEvent()));
notifier->setEnabled(true);
return true;
#else
return false;
#endif
}
#ifndef QESP_NO_UDEV
void QextSerialEnumeratorPrivate::_q_deviceEvent()
{
Q_Q(QextSerialEnumerator);
struct udev_device *dev = udev_monitor_receive_device(monitor);
if (dev) {
QextPortInfo pi = portInfoFromDevice(dev);
QLatin1String action(udev_device_get_action(dev));
if (action == QLatin1String("add"))
Q_EMIT q->deviceDiscovered(pi);
else if (action == QLatin1String("remove"))
Q_EMIT q->deviceRemoved(pi);
udev_device_unref(dev);
}
}
#endif

View File

@ -0,0 +1,307 @@
/****************************************************************************
** 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 "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <IOKit/serial/IOSerialKeys.h>
#include <CoreFoundation/CFNumber.h>
#include <sys/param.h>
void QextSerialEnumeratorPrivate::init_sys()
{
}
void QextSerialEnumeratorPrivate::destroy_sys()
{
IONotificationPortDestroy(notificationPortRef);
}
// static
QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
QList<QextPortInfo> infoList;
io_iterator_t serialPortIterator = 0;
kern_return_t kernResult = KERN_FAILURE;
CFMutableDictionaryRef matchingDictionary;
// first try to get any serialbsd devices, then try any USBCDC devices
if (!(matchingDictionary = IOServiceMatching(kIOSerialBSDServiceValue))) {
QESP_WARNING("IOServiceMatching returned a NULL dictionary.");
return infoList;
}
CFDictionaryAddValue(matchingDictionary, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
// then create the iterator with all the matching devices
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS) {
qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult;
return infoList;
}
iterateServicesOSX(serialPortIterator, infoList);
IOObjectRelease(serialPortIterator);
serialPortIterator = 0;
if (!(matchingDictionary = IOServiceNameMatching("AppleUSBCDC"))) {
QESP_WARNING("IOServiceNameMatching returned a NULL dictionary.");
return infoList;
}
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDictionary, &serialPortIterator) != KERN_SUCCESS) {
qCritical() << "IOServiceGetMatchingServices failed, returned" << kernResult;
return infoList;
}
iterateServicesOSX(serialPortIterator, infoList);
IOObjectRelease(serialPortIterator);
return infoList;
}
void QextSerialEnumeratorPrivate::iterateServicesOSX(io_object_t service, QList<QextPortInfo> &infoList)
{
// Iterate through all modems found.
io_object_t usbService;
while ((usbService = IOIteratorNext(service))) {
QextPortInfo info;
info.vendorID = 0;
info.productID = 0;
getServiceDetailsOSX(usbService, &info);
infoList.append(info);
}
}
bool QextSerialEnumeratorPrivate::getServiceDetailsOSX(io_object_t service, QextPortInfo *portInfo)
{
bool retval = true;
CFTypeRef bsdPathAsCFString = NULL;
CFTypeRef productNameAsCFString = NULL;
CFTypeRef vendorIdAsCFNumber = NULL;
CFTypeRef productIdAsCFNumber = NULL;
// check the name of the modem's callout device
bsdPathAsCFString = IORegistryEntryCreateCFProperty(service, CFSTR(kIOCalloutDeviceKey),
kCFAllocatorDefault, 0);
// wander up the hierarchy until we find the level that can give us the
// vendor/product IDs and the product name, if available
io_registry_entry_t parent;
kern_return_t kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
while (kernResult == KERN_SUCCESS && !vendorIdAsCFNumber && !productIdAsCFNumber) {
if (!productNameAsCFString)
productNameAsCFString = IORegistryEntrySearchCFProperty(parent,
kIOServicePlane,
CFSTR("Product Name"),
kCFAllocatorDefault, 0);
vendorIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
kIOServicePlane,
CFSTR(kUSBVendorID),
kCFAllocatorDefault, 0);
productIdAsCFNumber = IORegistryEntrySearchCFProperty(parent,
kIOServicePlane,
CFSTR(kUSBProductID),
kCFAllocatorDefault, 0);
io_registry_entry_t oldparent = parent;
kernResult = IORegistryEntryGetParentEntry(parent, kIOServicePlane, &parent);
IOObjectRelease(oldparent);
}
io_string_t ioPathName;
IORegistryEntryGetPath(service, kIOServicePlane, ioPathName);
portInfo->physName = ioPathName;
if (bsdPathAsCFString) {
char path[MAXPATHLEN];
if (CFStringGetCString((CFStringRef)bsdPathAsCFString, path,
PATH_MAX, kCFStringEncodingUTF8))
portInfo->portName = path;
CFRelease(bsdPathAsCFString);
}
if (productNameAsCFString) {
char productName[MAXPATHLEN];
if (CFStringGetCString((CFStringRef)productNameAsCFString, productName,
PATH_MAX, kCFStringEncodingUTF8))
portInfo->friendName = productName;
CFRelease(productNameAsCFString);
}
if (vendorIdAsCFNumber) {
SInt32 vID;
if (CFNumberGetValue((CFNumberRef)vendorIdAsCFNumber, kCFNumberSInt32Type, &vID))
portInfo->vendorID = vID;
CFRelease(vendorIdAsCFNumber);
}
if (productIdAsCFNumber) {
SInt32 pID;
if (CFNumberGetValue((CFNumberRef)productIdAsCFNumber, kCFNumberSInt32Type, &pID))
portInfo->productID = pID;
CFRelease(productIdAsCFNumber);
}
IOObjectRelease(service);
return retval;
}
// IOKit callbacks registered via setupNotifications()
void deviceDiscoveredCallbackOSX(void *ctxt, io_iterator_t serialPortIterator)
{
QextSerialEnumeratorPrivate *d = (QextSerialEnumeratorPrivate *)ctxt;
io_object_t serialService;
while ((serialService = IOIteratorNext(serialPortIterator)))
d->onDeviceDiscoveredOSX(serialService);
}
void deviceTerminatedCallbackOSX(void *ctxt, io_iterator_t serialPortIterator)
{
QextSerialEnumeratorPrivate *d = (QextSerialEnumeratorPrivate *)ctxt;
io_object_t serialService;
while ((serialService = IOIteratorNext(serialPortIterator)))
d->onDeviceTerminatedOSX(serialService);
}
/*
A device has been discovered via IOKit.
Create a QextPortInfo if possible, and emit the signal indicating that we've found it.
*/
void QextSerialEnumeratorPrivate::onDeviceDiscoveredOSX(io_object_t service)
{
Q_Q(QextSerialEnumerator);
QextPortInfo info;
info.vendorID = 0;
info.productID = 0;
if (getServiceDetailsOSX(service, &info))
Q_EMIT q->deviceDiscovered(info);
}
/*
Notification via IOKit that a device has been removed.
Create a QextPortInfo if possible, and emit the signal indicating that it's gone.
*/
void QextSerialEnumeratorPrivate::onDeviceTerminatedOSX(io_object_t service)
{
Q_Q(QextSerialEnumerator);
QextPortInfo info;
info.vendorID = 0;
info.productID = 0;
if (getServiceDetailsOSX(service, &info))
Q_EMIT q->deviceRemoved(info);
}
/*
Create matching dictionaries for the devices we want to get notifications for,
and add them to the current run loop. Invoke the callbacks that will be responding
to these notifications once to arm them, and discover any devices that
are currently connected at the time notifications are setup.
*/
bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool /*setup*/)
{
kern_return_t kernResult;
mach_port_t masterPort;
CFRunLoopSourceRef notificationRunLoopSource;
CFMutableDictionaryRef classesToMatch;
CFMutableDictionaryRef cdcClassesToMatch;
io_iterator_t portIterator;
kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
if (KERN_SUCCESS != kernResult) {
qDebug() << "IOMasterPort returned:" << kernResult;
return false;
}
classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue);
if (classesToMatch == NULL)
qDebug("IOServiceMatching returned a NULL dictionary.");
else
CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes));
if (!(cdcClassesToMatch = IOServiceNameMatching("AppleUSBCDC"))) {
QESP_WARNING("couldn't create cdc matching dict");
return false;
}
// Retain an additional reference since each call to IOServiceAddMatchingNotification consumes one.
classesToMatch = (CFMutableDictionaryRef) CFRetain(classesToMatch);
cdcClassesToMatch = (CFMutableDictionaryRef) CFRetain(cdcClassesToMatch);
notificationPortRef = IONotificationPortCreate(masterPort);
if (notificationPortRef == NULL) {
qDebug("IONotificationPortCreate return a NULL IONotificationPortRef.");
return false;
}
notificationRunLoopSource = IONotificationPortGetRunLoopSource(notificationPortRef);
if (notificationRunLoopSource == NULL) {
qDebug("IONotificationPortGetRunLoopSource returned NULL CFRunLoopSourceRef.");
return false;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), notificationRunLoopSource, kCFRunLoopDefaultMode);
kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, classesToMatch,
deviceDiscoveredCallbackOSX, this, &portIterator);
if (kernResult != KERN_SUCCESS) {
qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
return false;
}
// arm the callback, and grab any devices that are already connected
deviceDiscoveredCallbackOSX(this, portIterator);
kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOMatchedNotification, cdcClassesToMatch,
deviceDiscoveredCallbackOSX, this, &portIterator);
if (kernResult != KERN_SUCCESS) {
qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
return false;
}
// arm the callback, and grab any devices that are already connected
deviceDiscoveredCallbackOSX(this, portIterator);
kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, classesToMatch,
deviceTerminatedCallbackOSX, this, &portIterator);
if (kernResult != KERN_SUCCESS) {
qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
return false;
}
// arm the callback, and clear any devices that are terminated
deviceTerminatedCallbackOSX(this, portIterator);
kernResult = IOServiceAddMatchingNotification(notificationPortRef, kIOTerminatedNotification, cdcClassesToMatch,
deviceTerminatedCallbackOSX, this, &portIterator);
if (kernResult != KERN_SUCCESS) {
qDebug() << "IOServiceAddMatchingNotification return:" << kernResult;
return false;
}
// arm the callback, and clear any devices that are terminated
deviceTerminatedCallbackOSX(this, portIterator);
return true;
}

View File

@ -0,0 +1,123 @@
/****************************************************************************
** 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
** Copyright (c) 2012 Doug Brown
** 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 _QEXTSERIALENUMERATOR_P_H_
#define _QEXTSERIALENUMERATOR_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 "qextserialenumerator.h"
#ifdef Q_CC_MINGW
// needed for mingw to pull in appropriate dbt business...
// probably a better way to do this
// http://mingw-users.1079350.n2.nabble.com/DEV-BROADCAST-DEVICEINTERFACE-was-not-declared-in-this-scope-td3552762.html
// http://msdn.microsoft.com/en-us/library/6sehtctf.aspx
# ifndef WINVER
# define WINVER 0x0501
# endif
# ifndef _WIN32_WINNT
# define _WIN32_WINNT WINVER
# endif
#endif
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
#endif /*Q_OS_WIN*/
#ifdef Q_OS_MAC
# include <IOKit/usb/IOUSBLib.h>
#endif /*Q_OS_MAC*/
#if defined(Q_OS_LINUX) && !defined(QESP_NO_UDEV)
# include <QSocketNotifier>
extern "C" {
# include <libudev.h>
}
#endif
class QextSerialRegistrationWidget;
class QextSerialEnumeratorPrivate
{
Q_DECLARE_PUBLIC(QextSerialEnumerator)
public:
QextSerialEnumeratorPrivate(QextSerialEnumerator *enumrator);
~QextSerialEnumeratorPrivate();
void init_sys();
void destroy_sys();
static QList<QextPortInfo> getPorts_sys();
bool setUpNotifications_sys(bool setup);
#if defined(Q_OS_WIN) && defined(QT_GUI_LIB)
LRESULT onDeviceChanged(WPARAM wParam, LPARAM lParam);
bool matchAndDispatchChangedDevice(const QString &deviceID, const GUID &guid, WPARAM wParam);
QextSerialRegistrationWidget *notificationWidget;
#endif /*Q_OS_WIN*/
#ifdef Q_OS_MAC
/*!
* Search for serial ports using IOKit.
* \param infoList list with result.
*/
static void iterateServicesOSX(io_object_t service, QList<QextPortInfo> &infoList);
static bool getServiceDetailsOSX(io_object_t service, QextPortInfo *portInfo);
void onDeviceDiscoveredOSX(io_object_t service);
void onDeviceTerminatedOSX(io_object_t service);
friend void deviceDiscoveredCallbackOSX(void *ctxt, io_iterator_t serialPortIterator);
friend void deviceTerminatedCallbackOSX(void *ctxt, io_iterator_t serialPortIterator);
IONotificationPortRef notificationPortRef;
#endif // Q_OS_MAC
#if defined(Q_OS_LINUX) && !defined(QESP_NO_UDEV)
QSocketNotifier *notifier;
int notifierFd;
struct udev *udev;
struct udev_monitor *monitor;
void _q_deviceEvent();
#endif
private:
QextSerialEnumerator *q_ptr;
};
#endif //_QEXTSERIALENUMERATOR_P_H_

View File

@ -0,0 +1,56 @@
/****************************************************************************
** 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 "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
void QextSerialEnumeratorPrivate::init_sys()
{
}
void QextSerialEnumeratorPrivate::destroy_sys()
{
}
QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
QList<QextPortInfo> infoList;
QESP_WARNING("Enumeration for POSIX systems (except Linux) is not implemented yet.");
return infoList;
}
bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
{
Q_UNUSED(setup)
QESP_WARNING("Notifications for *Nix/FreeBSD are not implemented yet");
return false;
}

View File

@ -0,0 +1,303 @@
/****************************************************************************
** 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 "qextserialenumerator.h"
#include "qextserialenumerator_p.h"
#include <QtCore/QDebug>
#include <QtCore/QMetaType>
#include <QtCore/QRegExp>
#include <algorithm>
#include <objbase.h>
#include <initguid.h>
#include <setupapi.h>
#include <dbt.h>
#ifdef QT_GUI_LIB
/*!
\internal
\class QextSerialRegistrationWidget
Internal window which is used to receive device arrvial and removal message.
*/
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QtGui/QWidget>
class QextSerialRegistrationWidget : public QWidget
#else
#include <QtGui/QWindow>
class QextSerialRegistrationWidget : public QWindow
#endif
{
public:
QextSerialRegistrationWidget(QextSerialEnumeratorPrivate *qese) {
this->qese = qese;
}
~QextSerialRegistrationWidget() {}
protected:
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
bool winEvent(MSG *message, long *result) {
#else
bool nativeEvent(const QByteArray & /*eventType*/, void *msg, long *result) {
MSG *message = static_cast<MSG *>(msg);
#endif
if (message->message == WM_DEVICECHANGE) {
qese->onDeviceChanged(message->wParam, message->lParam);
*result = 1;
return true;
}
return false;
}
private:
QextSerialEnumeratorPrivate *qese;
};
#endif // QT_GUI_LIB
void QextSerialEnumeratorPrivate::init_sys()
{
#ifdef QT_GUI_LIB
notificationWidget = 0;
#endif // QT_GUI_LIB
}
/*!
default
*/
void QextSerialEnumeratorPrivate::destroy_sys()
{
#ifdef QT_GUI_LIB
if (notificationWidget)
delete notificationWidget;
#endif
}
#ifndef GUID_DEVINTERFACE_COMPORT
DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
#endif
/*!
\internal
Get value of specified property from the registry.
\a key handle to an open key.
\a property property name.
return property value.
*/
static QString getRegKeyValue(HKEY key, LPCTSTR property)
{
DWORD size = 0;
DWORD type;
if (::RegQueryValueEx(key, property, NULL, NULL, NULL, &size) != ERROR_SUCCESS)
return QString();
BYTE *buff = new BYTE[size];
QString result;
if (::RegQueryValueEx(key, property, NULL, &type, buff, &size) == ERROR_SUCCESS)
result = QString::fromUtf16(reinterpret_cast<ushort *>(buff));
delete [] buff;
return result;
}
/*!
\internal
Get specific property from registry.
\a devInfoSet pointer to the device information set that contains the interface
and its underlying device. Returned by SetupDiGetClassDevs() function.
\a devInfoData pointer to an SP_DEVINFO_DATA structure that defines the device instance.
this is returned by SetupDiGetDeviceInterfaceDetail() function.
\a property registry property. One of defined SPDRP_* constants.
return property string.
*/
static QString getDeviceRegistryProperty(HDEVINFO devInfoSet, PSP_DEVINFO_DATA devInfoData, DWORD property)
{
DWORD buffSize = 0;
::SetupDiGetDeviceRegistryProperty(devInfoSet, devInfoData, property, NULL, NULL, 0, &buffSize);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return QString();
BYTE *buff = new BYTE[buffSize];
::SetupDiGetDeviceRegistryProperty(devInfoSet, devInfoData, property, NULL, buff, buffSize, NULL);
QString result = QString::fromUtf16(reinterpret_cast<ushort *>(buff));
delete [] buff;
return result;
}
/*!
\internal
*/
static bool getDeviceDetailsInformation(QextPortInfo *portInfo, HDEVINFO devInfoSet, PSP_DEVINFO_DATA devInfoData
, WPARAM wParam = DBT_DEVICEARRIVAL)
{
portInfo->friendName = getDeviceRegistryProperty(devInfoSet, devInfoData, SPDRP_FRIENDLYNAME);
if (wParam == DBT_DEVICEARRIVAL)
portInfo->physName = getDeviceRegistryProperty(devInfoSet, devInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
portInfo->enumName = getDeviceRegistryProperty(devInfoSet, devInfoData, SPDRP_ENUMERATOR_NAME);
HKEY devKey = ::SetupDiOpenDevRegKey(devInfoSet, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
portInfo->portName = getRegKeyValue(devKey, TEXT("PortName"));
::RegCloseKey(devKey);
QString hardwareIDs = getDeviceRegistryProperty(devInfoSet, devInfoData, SPDRP_HARDWAREID);
QRegExp idRx(QLatin1String("VID_(\\w+)&PID_(\\w+)"));
if (hardwareIDs.toUpper().contains(idRx)) {
bool dummy;
portInfo->vendorID = idRx.cap(1).toInt(&dummy, 16);
portInfo->productID = idRx.cap(2).toInt(&dummy, 16);
//qDebug() << "got vid:" << vid << "pid:" << pid;
}
return true;
}
/*!
\internal
*/
static void enumerateDevices(const GUID &guid, QList<QextPortInfo> *infoList)
{
HDEVINFO devInfoSet = ::SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (devInfoSet != INVALID_HANDLE_VALUE) {
SP_DEVINFO_DATA devInfoData;
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(int i = 0; ::SetupDiEnumDeviceInfo(devInfoSet, i, &devInfoData); i++) {
QextPortInfo info;
info.productID = info.vendorID = 0;
getDeviceDetailsInformation(&info, devInfoSet, &devInfoData);
infoList->append(info);
}
::SetupDiDestroyDeviceInfoList(devInfoSet);
}
}
static bool lessThan(const QextPortInfo &s1, const QextPortInfo &s2)
{
if (s1.portName.startsWith(QLatin1String("COM"))
&& s2.portName.startsWith(QLatin1String("COM"))) {
return s1.portName.mid(3).toInt()<s2.portName.mid(3).toInt();
}
return s1.portName < s2.portName;
}
/*!
Get list of ports.
return list of ports currently available in the system.
*/
QList<QextPortInfo> QextSerialEnumeratorPrivate::getPorts_sys()
{
QList<QextPortInfo> ports;
enumerateDevices(GUID_DEVINTERFACE_COMPORT, &ports);
std::sort(ports.begin(), ports.end(), lessThan);
return ports;
}
/*
Enable event-driven notifications of board discovery/removal.
*/
bool QextSerialEnumeratorPrivate::setUpNotifications_sys(bool setup)
{
#ifndef QT_GUI_LIB
Q_UNUSED(setup)
QESP_WARNING("QextSerialEnumerator: GUI not enabled - can't register for device notifications.");
return false;
#else
Q_Q(QextSerialEnumerator);
if (setup && notificationWidget) //already setup
return true;
notificationWidget = new QextSerialRegistrationWidget(this);
DEV_BROADCAST_DEVICEINTERFACE dbh;
::ZeroMemory(&dbh, sizeof(dbh));
dbh.dbcc_size = sizeof(dbh);
dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
// dbh.dbcc_classguid = GUID_DEVCLASS_PORTS; //Ignored in such case
DWORD flags = DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES;
if (::RegisterDeviceNotification((HWND)notificationWidget->winId(), &dbh, flags) == NULL) {
QESP_WARNING() << "RegisterDeviceNotification failed:" << GetLastError();
return false;
}
// setting up notifications doesn't tell us about devices already connected
// so get those manually
foreach (QextPortInfo port, getPorts_sys())
Q_EMIT q->deviceDiscovered(port);
return true;
#endif // QT_GUI_LIB
}
#ifdef QT_GUI_LIB
LRESULT QextSerialEnumeratorPrivate::onDeviceChanged(WPARAM wParam, LPARAM lParam)
{
if (DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam) {
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
if (pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;
// delimiters are different across APIs...change to backslash. ugh.
QString deviceID = QString::fromUtf16(reinterpret_cast<ushort *>(pDevInf->dbcc_name));
deviceID = deviceID.toUpper().replace(QLatin1String("#"), QLatin1String("\\"));
matchAndDispatchChangedDevice(deviceID, GUID_DEVINTERFACE_COMPORT, wParam);
}
}
return 0;
}
bool QextSerialEnumeratorPrivate::matchAndDispatchChangedDevice(const QString &deviceID, const GUID &guid, WPARAM wParam)
{
Q_Q(QextSerialEnumerator);
bool rv = false;
DWORD dwFlag = (DBT_DEVICEARRIVAL == wParam) ? DIGCF_PRESENT : DIGCF_PROFILE;
HDEVINFO devInfoSet = SetupDiGetClassDevs(&guid, NULL, NULL, dwFlag | DIGCF_DEVICEINTERFACE);
if (devInfoSet != INVALID_HANDLE_VALUE) {
SP_DEVINFO_DATA spDevInfoData;
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for(int i=0; SetupDiEnumDeviceInfo(devInfoSet, i, &spDevInfoData); i++) {
DWORD nSize = 0;
TCHAR buf[MAX_PATH];
if (SetupDiGetDeviceInstanceId(devInfoSet, &spDevInfoData, buf, MAX_PATH, &nSize)
&& deviceID.contains(QString::fromUtf16(reinterpret_cast<ushort *>(buf)))) { // we found a match
rv = true;
QextPortInfo info;
info.productID = info.vendorID = 0;
getDeviceDetailsInformation(&info, devInfoSet, &spDevInfoData, wParam);
if (wParam == DBT_DEVICEARRIVAL)
Q_EMIT q->deviceDiscovered(info);
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
Q_EMIT q->deviceRemoved(info);
break;
}
}
SetupDiDestroyDeviceInfoList(devInfoSet);
}
return rv;
}
#endif //QT_GUI_LIB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,240 @@
/****************************************************************************
** 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

View File

@ -0,0 +1,36 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
PUBLIC_HEADERS += $$PWD/qextserialport.h \
$$PWD/qextserialenumerator.h \
$$PWD/qextserialport_global.h
HEADERS += $$PUBLIC_HEADERS \
$$PWD/qextserialport_p.h \
$$PWD/qextserialenumerator_p.h \
SOURCES += $$PWD/qextserialport.cpp \
$$PWD/qextserialenumerator.cpp
unix {
SOURCES += $$PWD/qextserialport_unix.cpp
linux* {
SOURCES += $$PWD/qextserialenumerator_linux.cpp
} else:macx {
SOURCES += $$PWD/qextserialenumerator_osx.cpp
} else {
SOURCES += $$PWD/qextserialenumerator_unix.cpp
}
}
win32:SOURCES += $$PWD/qextserialport_win.cpp \
$$PWD/qextserialenumerator_win.cpp
linux*{
!qesp_linux_udev:DEFINES += QESP_NO_UDEV
qesp_linux_udev: LIBS += -ludev
}
macx:LIBS += -framework IOKit -framework CoreFoundation
win32:LIBS += -lsetupapi -ladvapi32 -luser32
# moc doesn't detect Q_OS_LINUX correctly, so add this to make it work
linux*:DEFINES += __linux__

View 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

View File

@ -0,0 +1,250 @@
/****************************************************************************
** 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_

View File

@ -0,0 +1,458 @@
/****************************************************************************
** 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(&currentTermios); // 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(&currentTermios, B50);
break;
case BAUD75:
setBaudRate2Termios(&currentTermios, B75);
break;
case BAUD110:
setBaudRate2Termios(&currentTermios, B110);
break;
case BAUD134:
setBaudRate2Termios(&currentTermios, B134);
break;
case BAUD150:
setBaudRate2Termios(&currentTermios, B150);
break;
case BAUD200:
setBaudRate2Termios(&currentTermios, B200);
break;
case BAUD300:
setBaudRate2Termios(&currentTermios, B300);
break;
case BAUD600:
setBaudRate2Termios(&currentTermios, B600);
break;
case BAUD1200:
setBaudRate2Termios(&currentTermios, B1200);
break;
case BAUD1800:
setBaudRate2Termios(&currentTermios, B1800);
break;
case BAUD2400:
setBaudRate2Termios(&currentTermios, B2400);
break;
case BAUD4800:
setBaudRate2Termios(&currentTermios, B4800);
break;
case BAUD9600:
setBaudRate2Termios(&currentTermios, B9600);
break;
case BAUD19200:
setBaudRate2Termios(&currentTermios, B19200);
break;
case BAUD38400:
setBaudRate2Termios(&currentTermios, B38400);
break;
case BAUD57600:
setBaudRate2Termios(&currentTermios, B57600);
break;
#ifdef B76800
case BAUD76800:
setBaudRate2Termios(&currentTermios, B76800);
break;
#endif
case BAUD115200:
setBaudRate2Termios(&currentTermios, B115200);
break;
#if defined(B230400) && defined(B4000000)
case BAUD230400:
setBaudRate2Termios(&currentTermios, B230400);
break;
case BAUD460800:
setBaudRate2Termios(&currentTermios, B460800);
break;
case BAUD500000:
setBaudRate2Termios(&currentTermios, B500000);
break;
case BAUD576000:
setBaudRate2Termios(&currentTermios, B576000);
break;
case BAUD921600:
setBaudRate2Termios(&currentTermios, B921600);
break;
case BAUD1000000:
setBaudRate2Termios(&currentTermios, B1000000);
break;
case BAUD1152000:
setBaudRate2Termios(&currentTermios, B1152000);
break;
case BAUD1500000:
setBaudRate2Termios(&currentTermios, B1500000);
break;
case BAUD2000000:
setBaudRate2Termios(&currentTermios, B2000000);
break;
case BAUD2500000:
setBaudRate2Termios(&currentTermios, B2500000);
break;
case BAUD3000000:
setBaudRate2Termios(&currentTermios, B3000000);
break;
case BAUD3500000:
setBaudRate2Termios(&currentTermios, B3500000);
break;
case BAUD4000000:
setBaudRate2Termios(&currentTermios, B4000000);
break;
#endif
#ifdef Q_OS_MAC
default:
setBaudRate2Termios(&currentTermios, 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, &currentTermios);
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, &currentTermios);
currentTermios.c_cc[VTIME] = millisec/100;
::tcsetattr(fd, TCSAFLUSH, &currentTermios);
}
settingsDirtyFlags = 0;
}

View File

@ -0,0 +1,405 @@
/****************************************************************************
** 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/QRegExp>
#include <QtCore/QMetaType>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
# include <QtCore/QWinEventNotifier>
#else
# include <QtCore/private/qwineventnotifier_p.h>
#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 (fullName.contains(rx))
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;
QWriteLocker writelocker(bytesToWriteLock);
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)
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;
}

View File

@ -1,6 +1,9 @@
INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD DEPENDPATH += $$PWD
include($$PWD/extserial/src/qextserialport.pri)
HEADERS += $$PWD/Qss.h HEADERS += $$PWD/Qss.h
SOURCES += $$PWD/Qss.cpp SOURCES += $$PWD/Qss.cpp