mirror of
https://github.com/caperren/school_archives.git
synced 2025-11-09 21:51:15 +00:00
Added old firmware and pcb design files
These are all design documents that I thought I had lost. It's may make me cringe, but it's still cool to use it to see how far I've come.
This commit is contained in:
47
OSU SARL/Desktop Applications/EmbryoPickAndPlace/qextserialport-1.2rc/.gitignore
vendored
Normal file
47
OSU SARL/Desktop Applications/EmbryoPickAndPlace/qextserialport-1.2rc/.gitignore
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
syntax: glob
|
||||
*.pro.user*
|
||||
*.app
|
||||
*.moc
|
||||
*.prl
|
||||
Makefile*
|
||||
doc/html/
|
||||
*.framework/
|
||||
*.xcodeproj/
|
||||
debug/
|
||||
release/
|
||||
qtc-gdbmacros/
|
||||
*.rej
|
||||
*.orig
|
||||
*.obj
|
||||
*.swp
|
||||
*.dll
|
||||
*.exp
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.lib
|
||||
Thumbs.db
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
*.o
|
||||
*.so.*
|
||||
*.so
|
||||
*.pdb
|
||||
ui_*.h
|
||||
*~
|
||||
.qmake.cache
|
||||
extserialport.prf
|
||||
lib/*
|
||||
*.orig
|
||||
*.exe
|
||||
*.vcproj
|
||||
*.vcproj.*.user
|
||||
*_resource.rc
|
||||
*.sln
|
||||
*.idb
|
||||
*.ncb
|
||||
*.suo
|
||||
examples/enumerator/enumerator
|
||||
examples/event/event
|
||||
examples/qespta/qespta
|
||||
examples/uartassistant/uartassistant
|
||||
object_script.*
|
||||
@@ -0,0 +1,267 @@
|
||||
Change history for QextSerialPort (formerly QwSerialPort):
|
||||
(Lines beginning with + represent new functionality, * represent changed or
|
||||
fixed functionality, - represent removed or deprecated functionality)
|
||||
|
||||
Version 1.2 rc (2012 Debao Zhang)
|
||||
* Build-system refactor
|
||||
* Issue 145 : Custom baud support for MacOS
|
||||
* Issue 36 : Fix Devices Notification for Vista
|
||||
* Issue 54 and Issue 108 : Try detect more ports for windows
|
||||
* Issue 139 : Adjust the name of generated library
|
||||
- QextWinEventNotifier has been removed
|
||||
|
||||
Version 1.2 beta2 (2012 Debao Zhang)
|
||||
* Issue 124 : implement canReadLine
|
||||
* Issue 122 : make Dtr default to TRUE under Windows.
|
||||
* Issue 127 : fix QObject::MoveToThread brokes SerialPort on Windows
|
||||
* Issue 129 : Add custom baud support for Windows.
|
||||
* Issue 131 : Make sure portName returned by QextSerialEnumerator can be used by QextSerialPort
|
||||
* Issue 134 : Make "make install" really works
|
||||
* Issue 2: device discovery / removal notification on linux (read config_example.pri to figure out how to enable it.)
|
||||
|
||||
Version 1.2 beta1 (2012 Debao Zhang)
|
||||
* D-pointer and Q_PRIVATE_SLOT are used to moving private members from QextSerialPort to QextSerialPortPrivate
|
||||
* qdoc3 instead of doxygen is used for generating documents
|
||||
* MIT license header add to all sources files
|
||||
+ add a helper class QextWinEventNotifier for windows user, when user's SDK doesnot contain Qt's private files, this class will be auto selected.
|
||||
|
||||
Version 1.2win-alpha (2007 Michal Policht)
|
||||
+ Added QextSerialEnumerator pre-alpha. Works under W2k and later versions of Windows.
|
||||
+ Event driven mechanism (alternative to polling) is now available on Windows.
|
||||
- Removed default (=0) parameter from open() functions.
|
||||
* Fixed bug #1714917 in Win_QextSerialPort::close() method (by Kurt).
|
||||
* Fixed problem with lack of proper blocking in readData() on win32 (by Brandon Fosdick).
|
||||
* Removed QT_THREAD_SUPPORT option. Now QextSerialPort must be always compiled with threads support.
|
||||
* Mutexes are not static.
|
||||
* setTimeout() now accepts only one parameter.
|
||||
* bytesAvailable() on POSIX now shows 0 bytes instead of -1 when no bytes are available.
|
||||
* bytesAvailable() is const.
|
||||
* native POSIX file descriptors instead of QFile->handle() calls
|
||||
+ POSIX: Save and restore original termios when opening and closing the device
|
||||
* POSIX: Only disable special characters on systems that support it
|
||||
* POSIX: Use cfmakeraw(3) to get a non-canonical termios
|
||||
+ POSIX: Call close(2) in close() to actually close the device
|
||||
|
||||
Version 1.1 (official release)
|
||||
|
||||
Version 1.0.1
|
||||
* Minor changes (mostly in test application)
|
||||
|
||||
Version 1.0.0e (by Micha? Policht)
|
||||
* Fixed bytesAvailable(). Includes buffered bytes to the result.
|
||||
+ Added isSequential() method.
|
||||
+ Provided test application
|
||||
|
||||
Version 1.0.0d ( changes by Micha? Policht )
|
||||
- Removed isOpen() overriden declaration/implementation from qextserialport's classes. isOpen() relies on QIODevice now.
|
||||
- Removed bool portOpen variable. Replaced by internal QIODevice.openMode.
|
||||
- Removed getChar(), putChar() overriden declaration/implementation. QIODevice can handle this.
|
||||
* Calling open() with specified OpenMode invokes QIODevice::open() which result in proper openMode setting.
|
||||
* readData(), writeData() are protected as in QIODevice declaration.
|
||||
* QIODevice:: read() and write() function are working now (use them instead of readData() writeData()).
|
||||
* readData(), writeData() don't check if port is open any more (read() and write() assures that). The same behaviour can be found in QFile for example.
|
||||
* Fixed readLine().
|
||||
|
||||
* Fixed randomly crash on deletion bug on Windows ( by Stuart Nixon )
|
||||
http://lists.trolltech.com/qt-interest/2007-02/thread00340-0.html#msg00351
|
||||
|
||||
Version 0.9 (March 3, 2005) Stefan Sander <stefan-sander@users.sf.net>:
|
||||
+ Added a new precompiler constant, _TTY_FREEBSD_
|
||||
to support FreeBSD port names.
|
||||
+ Added _TTY_WIN_ constant in qextserialport.pro win32:DEFINES
|
||||
to have Windows port names as default when compiling on it.
|
||||
- Removed construct() call from QextSerialBase constructors,
|
||||
it is called indirectly through Win_QextSerialPort::construct()
|
||||
and Posix_QextSerialPort::construct().
|
||||
+ Added construct() call to Win_QextSerialPort constructors.
|
||||
+ Added setTimeout(0, 500) call to Win_QextSerialPort::construct().
|
||||
- Removed setTimeout(0, 500) call from Win_QextSerialPort(const char* name).
|
||||
* Fixed Posix_QextSerialPort::open(int) control flow, now the port settings
|
||||
are only applied if the associated file could be opened.
|
||||
* Fixed masking CR to NL, in Posix_CommConfig.c_iflag
|
||||
|
||||
Version 0.8 (, 2003) (Alpha release):
|
||||
* Added code to set the port timeouts in Win_QextSerialPort's default
|
||||
constructor.
|
||||
* Fixed Posix_QextSerialPort::construct() to set up the port correctly.
|
||||
* Fixed syntax errors in 2 ioctl() calls in posix_QextSerialPort.
|
||||
* lastError is now initialized to E_NO_ERROR in the QextSerialBase
|
||||
constructor.
|
||||
* The select() call in posix_QextSerialPort::bytesWaiting() is now
|
||||
properly coded. Previously it would always time out.
|
||||
* Fixed runtime errors in the ioctl() calls for
|
||||
Posix_QextSerialPort::setDtr() and Posix_QextSerialPort::setRts().
|
||||
Thanks to Marc Pignat.
|
||||
|
||||
Version 0.7 (June 15, 2002) <Bugfix release>:
|
||||
(0.61 - unofficial release)
|
||||
* Fixed a small bug in the initializations of the static members when
|
||||
QT_THREAD_SUPPORT was defined.
|
||||
* Fixed a bug that caused Borland's compiler to choke on Windows platforms
|
||||
(which perversely actually stemmed from a shortcoming of Visual C++ that
|
||||
Borland doesn't have).
|
||||
|
||||
(0.62 - unofficial release)
|
||||
* Fixed a bug that gave Q_LONG the wrong typedef for QT versions prior to
|
||||
3.0.
|
||||
|
||||
(0.63 - unofficial release)
|
||||
* Fixed 2 incorrect references to Posix_Comm_Config.
|
||||
* Fixed scoping of Posix_QextSerialPort::operator=().
|
||||
* Posix_QextSerialPort::construct should now be coded correctly.
|
||||
* Fixed return type for Posix_QextSerialPort::size().
|
||||
|
||||
(0.64 - unofficial release)
|
||||
* Fixed all the port settings functions to work properly when opening the
|
||||
port for the first time - previously none of the settings were being
|
||||
applied when the port was opened.
|
||||
* Fixed an oversight in Win_QextSerialPort::open() that caused the setting
|
||||
of port parameters to fail on NT and 2000 systems.
|
||||
|
||||
(0.7 - official release)
|
||||
* Fixed some calls to QextSerialBase constructors that no longer exist on
|
||||
the POSIX side.
|
||||
* Fixed the bad memcpy()'s in the POSIX copy constructor.
|
||||
* Fixed the Offset scoping problem under gcc 2.95.
|
||||
* The CBAUD flag has been deprecated on some POSIX systems. Fixed
|
||||
Posix_QextSerialPort::setBaudRate() to reflect this.
|
||||
* Added construct() calls to all of the Posix_QextSerialPort constructors.
|
||||
* Fixed double (and conflicting) typedefs of Offset when using QT versions
|
||||
prior to 3.0
|
||||
* Changed the call to CreateFile() to CreateFileA() in
|
||||
Win_QextSerialPort.cpp. This should get rid of problems for those using
|
||||
Unicode or other multibyte character sets for their string literals.
|
||||
* A few tweaks to the documentation.
|
||||
|
||||
- Removed the protected Posix_Handle variable from Posix_QextSerialPort.
|
||||
|
||||
Version 0.6 (March 11, 2002) <Bugfix release>:
|
||||
+ Added a new precompiler constant, QTVER_PRE_30. QT3 changed the return
|
||||
types of some QIODevice functions. Therefore, if compiling on versions
|
||||
of QT prior to 3.0, you should always define QTVER_PRE_30 in your project.
|
||||
Also had to add some preprocessor blocks to support both 3.0 and earlier
|
||||
versions of QT.
|
||||
+ Added implementations of 2 of the new constructors added in 0.5 to both
|
||||
Win_QextSerialPort and Posix_QextSerialPort.
|
||||
|
||||
* The scoping of the enums used in the PortSettings struct has been fixed.
|
||||
* QObject inheritance has been removed. This should not affect the
|
||||
functionality of the classes.
|
||||
* Replaced a few stray references to mutex->unlock() with UNLOCK_MUTEX() in
|
||||
the Windows code.
|
||||
* Fixed several runtime errors caused by calling nonexistent members of
|
||||
QextSerialBase.
|
||||
* Fixed a whole bunch of little things that were causing MSVC to choke when
|
||||
compiling for Windows.
|
||||
|
||||
Version 0.5 (February 15, 2002):
|
||||
+ There are 4 new macros (LOCK_MUTEX, UNLOCK_MUTEX, TTY_WARNING, and
|
||||
TTY_PORTABILITY_WARNING) that replace most of those ugly #ifdef blocks in
|
||||
the code.
|
||||
+ In place of the old namingConvention stuff, there is a new function,
|
||||
setName(). It is used to set the name of the device to be associated with
|
||||
the object. The new name() function can be used to retrieve the device
|
||||
name, which is stored in the new member variable portName.
|
||||
+ There is a new version of open() that takes a const char* as a parameter.
|
||||
It can be used to specify the name of the device when it is opened rather
|
||||
than at construction time.
|
||||
|
||||
* 3 constructors have been removed and 3 more added. There is now a copy
|
||||
constructor (and operator=()) as well as a constructor that takes a
|
||||
PortSettings structure as a parameter, and another that takes both a
|
||||
device name and a PortSettings structure. As a result of these changes
|
||||
the PortSettings structure declaration is no longer local to the
|
||||
QextSerialBase class. All of the removed constructors had to do with
|
||||
the setNamingConvention() system.
|
||||
* The static mutex member should now be reference-counted and only deleted
|
||||
when it is no longer referenced.
|
||||
* Most of the object construction duties have been pushed back into
|
||||
QextSerialBase
|
||||
* Fixed a couple resource leaks, mostly to do with unlocking the mutex
|
||||
properly
|
||||
|
||||
- Removed the setNamingConvention() nonsense.
|
||||
- Removed all QStrings and calls to sprintf() for thread compatibility.
|
||||
- Removed setNumber() functions as well as the portNumber member variable,
|
||||
as they were only necessary under the setNamingConvention() system.
|
||||
|
||||
I am grateful to Jorg Preiss (Preisz? Sorry, American keyboards don't have
|
||||
an ess-tset character ;)) for his invaluable input on most of the changes
|
||||
that went into this version.
|
||||
|
||||
Version 0.4 (March 20, 2001):
|
||||
+ All of the classes now derive from QObject as well as QIODevice. This
|
||||
is pretty much useless at the moment - signals and slots may be used
|
||||
to implement asynchronous communications in a future version
|
||||
+ Added configurable timeouts via the setTimeout() function. The default
|
||||
timeout for read and write operations is now 500 milliseconds
|
||||
+ There is now a functional .pro file for the library (thanks to
|
||||
Gunnstein Lye)
|
||||
+ The prefixes for all of the classes have changed from Qw to Qext, in
|
||||
compliance with the qt-addons project standard
|
||||
|
||||
* Fixed a bug that caused port settings to be restored incorrectly when
|
||||
switching ports with setNumber()
|
||||
* Minor changes to QextSerialBase::setNumber(). Functionality should now
|
||||
reflect the documentation, which has also been updated to reflect the
|
||||
changes that went in on version 0.3.
|
||||
* Some fixes to the documentation. The Posix_QextSerialPort and
|
||||
Win_QextSerialPort classes should no longer have any unnecessary
|
||||
references to inapplicable platforms, and the documentation for open() has
|
||||
been updated.
|
||||
* Should now compile without QT_THREAD_SUPPORT defined (ie, in single-
|
||||
threaded environments), although it will require slight changes to the
|
||||
makefile (tmake "CONFIG-=thread" should work)
|
||||
* Fixed a few compilation issues, especially on the POSIX side (should
|
||||
compile under Linux now :))
|
||||
* POSIX code is a little cleaner and more efficient
|
||||
* Various small fixes to the documentation
|
||||
* Constants now follow a consistent naming convention, with underscores at
|
||||
the beginning and end of each. For example TTY_POSIX has become
|
||||
_TTY_POSIX_
|
||||
|
||||
Version 0.3 (Feb. 14, 2001):
|
||||
+ Added a warning that appears when QwSerialPort is compiled on a POSIX
|
||||
platform that does not implement 76800 baud operation. In this situation
|
||||
QwSerialPort will also switch to 57600 baud.
|
||||
+ Major code reorganization - there are now 4 classes instead of 1. This
|
||||
should remove a lot of the #ifdef...#else...#endif constructs and
|
||||
hopefully make the code easier to read. Including the class in your
|
||||
project is still done by including QwSerialPort.h and instantiating a
|
||||
QwSerialPort object.
|
||||
|
||||
* The serial port associated with a QwSerialPort object is no longer
|
||||
opened on construction, or upon calling the setNumber() function. You
|
||||
must now explicitly call open() to open the port.
|
||||
|
||||
Version 0.2 (Jan. 3, 2001):
|
||||
+ Added lastError() function with rudimentary error codes
|
||||
+ Better documentation
|
||||
+ Added ability to examine the empty/not empty state of a port's input
|
||||
buffer with atEnd()
|
||||
+ Added ability to retrieve the number of bytes in a port's input buffer
|
||||
with size() (thanks to Olivier Tubach)
|
||||
+ Added ability to turn off portability warnings by defining
|
||||
TTY_NOWARN_PORT in your project
|
||||
+ Added ability to turn off all warning messages by defining TTY_NOWARN
|
||||
in your project
|
||||
+ Added ability to select POSIX serial functions in Windows NT/2000 by
|
||||
defining TTY_POSIX in your project (untested)
|
||||
+ Added control over RTS and DTR lines with setRts() and setDtr()
|
||||
respectively
|
||||
+ Added ability to query line status using lineStatus().
|
||||
+ Added readLine() functionality (thanks to Olivier Tubach)
|
||||
+ Added bytesWaiting(), a non-const/thread-safe version of size()
|
||||
+ The class should now be thread-safe through the use of a recursive
|
||||
QMutex (untested)
|
||||
|
||||
* Fixed a bug that could cause hardware flow control not to work on some
|
||||
POSIX systems
|
||||
* Put in a few missing fileno() calls in the POSIX code
|
||||
* Fixed a few syntax errors that caused compilation to fail on POSIX systems
|
||||
|
||||
- BAUD0 is no longer a valid baud rate setting - to drop the DTR line,
|
||||
call setDtr(FALSE)
|
||||
|
||||
Version 0.1 (Dec. 11, 2000):
|
||||
Initial public release.
|
||||
@@ -0,0 +1,94 @@
|
||||
From QextSerialPort 1.2-beta on, we use MIT license for QextSerialPort project.
|
||||
|
||||
== License ==
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
== Why license needed? ==
|
||||
|
||||
Many users complains that, without a proper licence they can not use this library.
|
||||
|
||||
* http://groups.google.com/group/qextserialport/browse_thread/thread/0e8756920b01da82
|
||||
|
||||
Hi,
|
||||
we are considering using a modified version of QExtSerialPort in one of our
|
||||
projects (Qt Creator, http://qt.gitorious.org/qt-creator).
|
||||
Would it be possible to add license header information or a license file to the
|
||||
QExtSerialPort code base? - This would make re-use of the code base easier.
|
||||
If that is not possible, could we redistribute the source code with BSD-
|
||||
license headers manually added?
|
||||
|
||||
And
|
||||
|
||||
I am also considering packaging the software for Debian, but I
|
||||
couldn't do it yet just because of the license.
|
||||
|
||||
* http://code.google.com/p/qextserialport/issues/detail?id=8
|
||||
|
||||
Questions:
|
||||
Can I use qextserialport in a commercial product?
|
||||
If yes, how?
|
||||
Compile it in? I guess no.
|
||||
If I can use it as a library, how should the README be formulated?
|
||||
Is the "MIT license" from 2008 appropriate?
|
||||
|
||||
== Why can we use MIT? ==
|
||||
|
||||
Form the history of [http://lists.trolltech.com/qt-interest/2004-12/msg01022.html qt-interest mail list]
|
||||
|
||||
* Wayne Roth, the original author of the project, had said that:
|
||||
|
||||
the code is in the public domain. Do whatever you like with it. Right
|
||||
now I have too many other things to do to put any serious time into
|
||||
fixing it. Trolltech should be aware of this already; they asked
|
||||
about a license when they offered to host the tarball.
|
||||
|
||||
* Stefan Sander, the maintainer of qextserialport on sourceforge, said that
|
||||
|
||||
Hello,
|
||||
My project registration at !SourceForge have been approved.
|
||||
http://www.sf.net/projects/qextserialport
|
||||
I thought an initial licence of Public Domain would be best solution.
|
||||
Someone wrote: - Because its public domain, some could fork it under different licenses -
|
||||
|
||||
And from [http://groups.google.com/group/qextserialport/browse_thread/thread/fbcddbfb4a0b5a51?pli=1 this thread] on qesp mail list, we can see that, current maintainers and users agree with a MIT licence.
|
||||
|
||||
* Brandon Fosdick,
|
||||
|
||||
I would vote for BSD or MIT :)
|
||||
|
||||
* Liam Staskawicz,
|
||||
|
||||
That works for me - let's call it MIT and go for it :)
|
||||
|
||||
And from [[https://groups.google.com/forum/?fromgroups#!topic/qextserialport/P_5TrNHBICE this other thread]] on the same mailing list:
|
||||
|
||||
* Michal Policht,
|
||||
|
||||
I agree to license.
|
||||
@@ -0,0 +1,64 @@
|
||||
= About QextSerialPort =
|
||||
|
||||
QextSerialPort provides an interface to old fashioned serial ports for Qt-based applications. It currently supports Mac OS X, Windows, Linux, FreeBSD.
|
||||
|
||||
http://code.google.com/p/qextserialport/
|
||||
|
||||
== How to use (1) ==
|
||||
|
||||
* Download the source code.
|
||||
|
||||
* Put the source code in any directory you like. For example, 3rdparty:
|
||||
|
||||
|-- project.pro
|
||||
|-- ....
|
||||
|-- 3rdparty\
|
||||
| |-- qextserialport\
|
||||
| |
|
||||
|
||||
* Add following line to your qmake project file:
|
||||
|
||||
include(3rdparty/qextserialport/src/qextserialport.pri)
|
||||
|
||||
* Using QextSerialPort in your code. Enjoy it!
|
||||
|
||||
#include "qextserialport.h"
|
||||
....
|
||||
QextSerialPort * port = new QextSerialPort();
|
||||
....
|
||||
|
||||
== How to use (2) ==
|
||||
It's very easy to compile QextSerialPort directly into your application
|
||||
(see above section), however, we would prefer to use it as a shared library.
|
||||
|
||||
* Download the source code, and put it in any location you like.
|
||||
|
||||
* Run following command to generate library.
|
||||
|
||||
qmake
|
||||
make (or nmake)
|
||||
sudo make install (or nmake install)
|
||||
|
||||
* Add following line to your project's file
|
||||
|
||||
CONFIG += extserialport
|
||||
|
||||
* Using QextSerialPort in your code. Enjoy it!
|
||||
|
||||
#include "qextserialport.h"
|
||||
....
|
||||
QextSerialPort * port = new QextSerialPort();
|
||||
....
|
||||
|
||||
== Build Documents ==
|
||||
* Run
|
||||
qmake
|
||||
make docs
|
||||
|
||||
* Note: More information can be found in doc/readme.txt
|
||||
|
||||
== Build examples ==
|
||||
* Goto examples directory, then run
|
||||
qmake (or qmake -r)
|
||||
make (or nmake)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,12 @@
|
||||
OTHER_FILES += $$PWD/qextserialport.qdocconf
|
||||
|
||||
#name of qdoc3 has been changed to qdoc under Qt5
|
||||
QESP_QDOC = qdoc
|
||||
lessThan(QT_MAJOR_VERSION, 5):QESP_QDOC = qdoc3
|
||||
|
||||
docs_target.target = docs
|
||||
docs_target.commands = $$QESP_QDOC $$PWD/qextserialport.qdocconf
|
||||
|
||||
QMAKE_EXTRA_TARGETS = docs_target
|
||||
QMAKE_CLEAN += "-r $$PWD/html"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,16 @@
|
||||
/*!
|
||||
\example examples/enumerator
|
||||
\title enumerator Demo
|
||||
|
||||
The example demonstrates how to use QextSerialEnumerator.
|
||||
|
||||
Include the proper header file
|
||||
\snippet examples/enumerator/main.cpp 0
|
||||
|
||||
Get available ports in the system.
|
||||
\snippet examples/enumerator/main.cpp 1
|
||||
|
||||
Output
|
||||
\snippet examples/enumerator/main.cpp 2
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
\example examples/qespta
|
||||
\title qespta Demo
|
||||
|
||||
The example demonstrates how to use QextSerialPort.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
\example examples/uartassistant
|
||||
\title UartAssistant Demo
|
||||
|
||||
The example demonstrates how to use QextSerialPort.
|
||||
|
||||
Initialze UI element.
|
||||
\snippet examples/uartassistant/dialog.cpp 0
|
||||
|
||||
Initialize serial port
|
||||
\snippet examples/uartassistant/dialog.cpp 1
|
||||
|
||||
port Settings
|
||||
\snippet examples/uartassistant/dialog.cpp 2
|
||||
|
||||
Open or Close the port.
|
||||
\snippet examples/uartassistant/dialog.cpp 3
|
||||
|
||||
Read from or Write to the port
|
||||
\snippet examples/uartassistant/dialog.cpp 4
|
||||
|
||||
\image uartassistant.png
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/*!
|
||||
\page index.html
|
||||
\title QextSerialPort Manual
|
||||
|
||||
\section1 Overview
|
||||
QextSerialPort provides an interface to old fashioned serial ports for
|
||||
Qt-based applications. It currently supports Mac OS X, Windows, Linux, FreeBSD.
|
||||
|
||||
From QextSerialPort 1.2-beta on, license of the project has been changed to MIT.
|
||||
|
||||
\list
|
||||
\o Revision 0.9.x is Qt 2 & 3 compatible.
|
||||
\o Revision 1.x.x is Qt 4 compatible.
|
||||
\o From revision 1.2beta1 on, Qt 5 support is added.
|
||||
\endlist
|
||||
|
||||
|
||||
\section1 Classes
|
||||
\list
|
||||
\o \l QextSerialPort encapsulates a serial port on both POSIX and Windows systems.
|
||||
\o \l QextSerialEnumerator enumerates ports currently available in the system.
|
||||
\endlist
|
||||
|
||||
\section1 Getting Started
|
||||
|
||||
|
||||
\section2 Usage(1): Source Code Only
|
||||
|
||||
The package contains a qextserialport.pri file that allows you to integrate the component into programs that use qmake for the build step.
|
||||
|
||||
Download the source code.
|
||||
Put the source code in any directory you like. For example, 3rdparty:
|
||||
|
||||
\code
|
||||
|-- project.pro
|
||||
|-- ....
|
||||
|-- 3rdparty\
|
||||
| |-- qextserialport\
|
||||
| |
|
||||
\endcode
|
||||
|
||||
Add following line to your qmake project file:
|
||||
\code
|
||||
include(pathToPri/qextserialport.pri)
|
||||
\endcode
|
||||
|
||||
Then, using QextSerialPort in your code
|
||||
\code
|
||||
#include "qextserialport.h"
|
||||
...
|
||||
MyClass::MyClass()
|
||||
{
|
||||
port = new QextSerialPort("COM1");
|
||||
connect(port, SIGNAL(readyRead()), this, SLOT(onDataAvailable()));
|
||||
port->open();
|
||||
}
|
||||
|
||||
void MyClass::onDataAvailable()
|
||||
{
|
||||
QByteArray data = port->readAll();
|
||||
processNewData(usbdata);
|
||||
}
|
||||
\endcode
|
||||
|
||||
\section2 Usage(2): shared library
|
||||
Although QextSerialPort can be directly compiled into your application, You may prefer
|
||||
to use QextSerailPort as an library, which is very easy too.
|
||||
|
||||
1. Download the source code, and put it in any location you like.
|
||||
|
||||
2. Goto the top level directory ,run following command to generate library.
|
||||
|
||||
\code
|
||||
qmake
|
||||
sudo make install (or nmake install)
|
||||
\endcode
|
||||
|
||||
3. Add following line to your project's file
|
||||
|
||||
\code
|
||||
CONFIG += extserialport
|
||||
\endcode
|
||||
|
||||
4. Using QextSerialPort in your code. Enjoy it!
|
||||
|
||||
\code
|
||||
#include "qextserialport.h"
|
||||
....
|
||||
QextSerialPort * port = new QextSerialPort();
|
||||
....
|
||||
\endcode
|
||||
|
||||
\section2 Usage(3): Static library
|
||||
|
||||
Someone prefer to use QextSerailPort as static library.
|
||||
|
||||
Open the project file: qextserialport.pro, add uncomment follow line
|
||||
|
||||
\code
|
||||
# CONFIG += qesp_static
|
||||
\endcode
|
||||
|
||||
Then follow the same steps as shared library
|
||||
|
||||
\code
|
||||
qmake
|
||||
sudo make install
|
||||
\endcode
|
||||
|
||||
The static library, the header files, and the feature file will be installed to your system.
|
||||
|
||||
Add following line to your qmake's project file:
|
||||
|
||||
\code
|
||||
CONFIG += extserialport
|
||||
\endcode
|
||||
|
||||
\section1 Platform Special
|
||||
|
||||
\section2 For MacX: Build as framework
|
||||
|
||||
Open the project file: *qextserialport.pro*, and uncomment follow line
|
||||
|
||||
\code
|
||||
# CONFIG += qesp_mac_framework
|
||||
\endcode
|
||||
|
||||
Then follow the same steps as shared library, Goto the top level directory , and run
|
||||
|
||||
\code
|
||||
qmake
|
||||
sudo make install
|
||||
\endcode
|
||||
|
||||
The framework which includes libraries and the header files, and the feature file will be installed to your system.
|
||||
|
||||
Add following line to your qmake's project file:
|
||||
|
||||
\code
|
||||
CONFIG += extserialport
|
||||
\endcode
|
||||
|
||||
\section2 For Linux: Enable udev
|
||||
|
||||
Open the project file: *qextserialport.pro*, uncomment follow line
|
||||
|
||||
\code
|
||||
#linux*:CONFIG += qesp_linux_udev
|
||||
\endcode
|
||||
|
||||
Note, If you are using the usage(1), Add following line before include the qextserialport.pri file.
|
||||
\code
|
||||
CONFIG += qesp_linux_udev
|
||||
\endcode
|
||||
|
||||
|
||||
\section2 Build documents
|
||||
\code
|
||||
make docs
|
||||
\endcode
|
||||
|
||||
\section1 Examples
|
||||
\list
|
||||
\o \l examples/enumerator
|
||||
\o \l examples/qespta
|
||||
\o \l examples/uartassistant
|
||||
\endlist
|
||||
|
||||
\section1 Resources
|
||||
\section2 Nokia(Trolltech)
|
||||
\list
|
||||
\o \l {http://doc.trolltech.com/qq/qq12-iodevice.html} {Writing a Custom I/O Device}
|
||||
\o \l {http://doc.trolltech.com/3.3/qiodevice.html} {Qt 3.3: QIODevice Class Reference}
|
||||
\o \l {http://doc.trolltech.com/4.7/qiodevice.html} {Qt 4.7: QIODevice Class Reference}
|
||||
\endlist
|
||||
\section2 MSDN
|
||||
\list
|
||||
\o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_resources.asp} {Communications Resources}
|
||||
\o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/about_communications_resources.asp} {About Communications Resources}
|
||||
\o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/using_communications_resources.asp}{Using Communications Resources}
|
||||
\o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_functions.asp} {Communications Functions}
|
||||
\o \l {http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/communications_structures.asp} {Communications Structures}
|
||||
\endlist
|
||||
\section2 TLDP
|
||||
\list
|
||||
\o \l {http://www.tldp.org/HOWTO/Serial-HOWTO.html}{Serial HOWTO}
|
||||
\o \l {http://www.tldp.org/HOWTO/Serial-Programming-HOWTO/}{Serial Programming HOWTO}
|
||||
\endlist
|
||||
\section2 Other
|
||||
\list
|
||||
\o \l {http://www.easysw.com/~mike/serial/serial.html} {Serial Programming Guide for POSIX Operating Systems}
|
||||
\endlist
|
||||
|
||||
*/
|
||||
|
||||
/*!
|
||||
\page classes.html
|
||||
\generatelist annotatedclasses
|
||||
*/
|
||||
@@ -0,0 +1,53 @@
|
||||
# Run qdoc3 from the directory that contains this file.
|
||||
project = qesp
|
||||
description = QextSerialPort Reference Documentation
|
||||
url = http://code.google.com/p/qextserialport
|
||||
|
||||
outputencoding = UTF-8
|
||||
language = Cpp
|
||||
|
||||
#Paths are relative to the location of this file
|
||||
headerdirs = . ../src
|
||||
sourcedirs = . ../src
|
||||
exampledirs = ../examples ..
|
||||
imagedirs = ./examples/images images
|
||||
|
||||
Cpp.ignoretokens = QEXTSERIALPORT_EXPORT
|
||||
|
||||
indexes = $QTDIR/doc/html/qt.index
|
||||
|
||||
qhp.projects = qesp
|
||||
qhp.qesp.file = qesp.qhp
|
||||
qhp.qesp.namespace = com.google.code.qextserialport.120
|
||||
qhp.qesp.virtualFolder = qdoc
|
||||
qhp.qesp.indexTitle = QextSerialPort Reference Documentation
|
||||
qhp.qesp.indexRoot =
|
||||
qhp.qesp.extraFiles = style/style.css
|
||||
|
||||
|
||||
#------------------------------------------------------------------
|
||||
outputdir = html
|
||||
outputformats = HTML
|
||||
|
||||
headers.fileextensions = "*.h"
|
||||
sources.fileextensions = "*.cpp *.qdoc"
|
||||
|
||||
HTML.templatedir = .
|
||||
HTML.stylesheets = style/style.css
|
||||
|
||||
HTML.headerstyles = " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n"
|
||||
HTML.endheader = "</head>\n"
|
||||
|
||||
HTML.postheader = "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n" \
|
||||
"<tr>\n" \
|
||||
"<td class=\"postheader\" valign=\"center\">" \
|
||||
"<a href=\"index.html\">Home</a> ·" \
|
||||
" <a href=\"classes.html\">All Classes</a> ·" \
|
||||
"</td></tr></table>"
|
||||
|
||||
HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
|
||||
"<table width=\"100%\" cellspacing=\"0\" border=\"0\"><tr class=\"address\">\n" \
|
||||
"<td width=\"40%\" align=\"left\">Copyright © 2000-2012</td>\n" \
|
||||
"<td width=\"20%\" align=\"center\"><a href=\"http://code.google.com/p/qextserialport\">QextSerialPort Project</a></td>\n" \
|
||||
"<td width=\"40%\" align=\"right\"><div align=\"right\">QextSerialPort Manual</div></td>\n" \
|
||||
"</tr></table></div></address>"
|
||||
@@ -0,0 +1,35 @@
|
||||
Note:
|
||||
|
||||
If you are using qextserialport-XXX.tar.gz, the qesp.qch and
|
||||
html files have been provided.
|
||||
|
||||
Open the file "html/index.html" using your web browser.
|
||||
Or integrated the "html/qesp.qch" into your QtCreator.
|
||||
|
||||
|
||||
== How to generate help files? ==
|
||||
|
||||
Simply run following commands at toplevel directory.
|
||||
qmake
|
||||
make docs
|
||||
|
||||
Or run the following command at this directory
|
||||
qdoc3 qextserialport.qdocconf
|
||||
|
||||
Then a folder called "html" will be generated.
|
||||
Open the file "html/index.html" using your web browser.
|
||||
|
||||
== How to integrated into Qt Creator or Qt Assistant? ==
|
||||
|
||||
Once the html files are generated. run following commands
|
||||
cd doc/html
|
||||
qhelpgenerator qesp.qhp
|
||||
|
||||
A file called "qesp.qch" will be generated.
|
||||
|
||||
For Qt Assistant:
|
||||
Edit ==> Preferences ==> Documentations ==> Add...
|
||||
|
||||
For Qt Creator
|
||||
Tools ==> Options ==> Help ==> Documentations ==> Add...
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,137 @@
|
||||
a:link, a:visited {
|
||||
color: #00732F;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
body {
|
||||
font: normal 400 14px/1.2 Arial;
|
||||
margin-top: 85px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: 500 20px/1.2 Arial;
|
||||
}
|
||||
|
||||
h3.fn, span.fn {
|
||||
-moz-border-radius: 7px 7px 7px 7px;
|
||||
-webkit-border-radius: 7px 7px 7px 7px;
|
||||
border-radius: 7px 7px 7px 7px;
|
||||
background-color: #F6F6F6;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: #E6E6E6;
|
||||
word-spacing: 3px;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
|
||||
table, pre {
|
||||
-moz-border-radius: 7px 7px 7px 7px;
|
||||
-webkit-border-radius: 7px 7px 7px 7px;
|
||||
border-radius: 7px 7px 7px 7px;
|
||||
background-color: #F6F6F6;
|
||||
border: 1px solid #E6E6E6;
|
||||
border-collapse: separate;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 25px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: 3px 15px 3px 20px;
|
||||
}
|
||||
|
||||
table tr.even {
|
||||
background-color: white;
|
||||
color: #66666E;
|
||||
}
|
||||
|
||||
table tr.odd {
|
||||
background-color: #F6F6F6;
|
||||
color: #66666E;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 10px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.cpp {
|
||||
display: block;
|
||||
margin: 10;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
padding: 20px 0 20px 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.memItemLeft {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.memItemRight {
|
||||
padding: 3px 15px 3px 0;
|
||||
}
|
||||
|
||||
.qml {
|
||||
display: block;
|
||||
margin: 10;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
padding: 20px 0 20px 0;
|
||||
}
|
||||
|
||||
.qmldefault {
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color: red;
|
||||
}
|
||||
|
||||
.qmlreadonly {
|
||||
padding-left: 5px;
|
||||
float: right;
|
||||
color: #254117;
|
||||
}
|
||||
|
||||
.rightAlign {
|
||||
padding: 3px 5px 3px 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: white;
|
||||
color: #44A51C;
|
||||
font-family: Verdana;
|
||||
font-size: 35px;
|
||||
font-weight: normal;
|
||||
left: 0;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 16px;
|
||||
padding-top: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.toc {
|
||||
float: right;
|
||||
-moz-border-radius: 7px 7px 7px 7px;
|
||||
-webkit-border-radius: 7px 7px 7px 7px;
|
||||
border-radius: 7px 7px 7px 7px;
|
||||
background-color: #F6F6F6;
|
||||
border: 1px solid #DDD;
|
||||
margin: 0 20px 10px 10px;
|
||||
padding: 20px 15px 20px 20px;
|
||||
height: auto;
|
||||
width: 200px;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,6 @@
|
||||
TEMPLATE = app
|
||||
DEPENDPATH += .
|
||||
CONFIG += console
|
||||
include(../../src/qextserialport.pri)
|
||||
SOURCES += main.cpp
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Main file.
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
//! [0]
|
||||
#include "qextserialenumerator.h"
|
||||
//! [0]
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QDebug>
|
||||
int main()
|
||||
{
|
||||
//! [1]
|
||||
QList<QextPortInfo> ports = QextSerialEnumerator::getPorts();
|
||||
//! [1]
|
||||
qDebug() << "List of ports:";
|
||||
//! [2]
|
||||
foreach (QextPortInfo info, ports) {
|
||||
qDebug() << "port name:" << info.portName;
|
||||
qDebug() << "friendly name:" << info.friendName;
|
||||
qDebug() << "physical name:" << info.physName;
|
||||
qDebug() << "enumerator name:" << info.enumName;
|
||||
qDebug() << "vendor ID:" << info.vendorID;
|
||||
qDebug() << "product ID:" << info.productID;
|
||||
|
||||
qDebug() << "===================================";
|
||||
}
|
||||
//! [2]
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
#include "PortListener.h"
|
||||
#include <QtDebug>
|
||||
|
||||
PortListener::PortListener(const QString &portName)
|
||||
{
|
||||
qDebug() << "hi there";
|
||||
this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
|
||||
port->setBaudRate(BAUD9600);
|
||||
port->setFlowControl(FLOW_OFF);
|
||||
port->setParity(PAR_NONE);
|
||||
port->setDataBits(DATA_8);
|
||||
port->setStopBits(STOP_2);
|
||||
|
||||
if (port->open(QIODevice::ReadWrite) == true) {
|
||||
connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
|
||||
connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
|
||||
if (!(port->lineStatus() & LS_DSR))
|
||||
qDebug() << "warning: device is not turned on";
|
||||
qDebug() << "listening for data on" << port->portName();
|
||||
}
|
||||
else {
|
||||
qDebug() << "device failed to open:" << port->errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void PortListener::onReadyRead()
|
||||
{
|
||||
QByteArray bytes;
|
||||
int a = port->bytesAvailable();
|
||||
bytes.resize(a);
|
||||
port->read(bytes.data(), bytes.size());
|
||||
qDebug() << "bytes read:" << bytes.size();
|
||||
qDebug() << "bytes:" << bytes;
|
||||
}
|
||||
|
||||
void PortListener::onDsrChanged(bool status)
|
||||
{
|
||||
if (status)
|
||||
qDebug() << "device was turned on";
|
||||
else
|
||||
qDebug() << "device was turned off";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
|
||||
#ifndef PORTLISTENER_H_
|
||||
#define PORTLISTENER_H_
|
||||
|
||||
#include <QObject>
|
||||
#include "qextserialport.h"
|
||||
|
||||
class PortListener : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PortListener(const QString &portName);
|
||||
|
||||
private:
|
||||
QextSerialPort *port;
|
||||
|
||||
private slots:
|
||||
void onReadyRead();
|
||||
void onDsrChanged(bool status);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /*PORTLISTENER_H_*/
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,7 @@
|
||||
TEMPLATE = app
|
||||
DEPENDPATH += .
|
||||
CONFIG += console
|
||||
include(../../src/qextserialport.pri)
|
||||
|
||||
SOURCES += main.cpp PortListener.cpp
|
||||
HEADERS += PortListener.h
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Main file.
|
||||
* @author Michal Policht
|
||||
*/
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include "PortListener.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QString portName = QLatin1String("COM1"); // update this to use your port of choice
|
||||
PortListener listener(portName); // signals get hooked up internally
|
||||
|
||||
// start the event loop and wait for signals
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = qespta enumerator \
|
||||
uartassistant
|
||||
win32:SUBDIRS += event
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file MainWindow.cpp
|
||||
* @brief MainWindow Implementation.
|
||||
* @see MainWindow.h
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QMenuBar>
|
||||
#include "MainWindow.h"
|
||||
#include "MessageWindow.h"
|
||||
#include "QespTest.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
{
|
||||
//central widget
|
||||
QespTest *qespTest = new QespTest();
|
||||
setCentralWidget(qespTest);
|
||||
//bottom dock widget
|
||||
MessageWindow *msgWindow = new MessageWindow();
|
||||
addDockWidget(Qt::BottomDockWidgetArea, msgWindow);
|
||||
|
||||
createActions();
|
||||
createMenus();
|
||||
|
||||
setWindowTitle(tr("QextSerialPort Test Application"));
|
||||
}
|
||||
|
||||
void MainWindow::about()
|
||||
{
|
||||
QMessageBox::about(this, tr("About "),
|
||||
tr("<B>""</B><BR>"
|
||||
"author: Michal Policht<br>"
|
||||
"<a href='mailto:xpolik@users.sourceforge.net'>xpolik@users.sourceforge.net</a>"));
|
||||
}
|
||||
|
||||
void MainWindow::createActions()
|
||||
{
|
||||
//File actions
|
||||
exitAct = new QAction(tr("E&xit"), this);
|
||||
exitAct->setShortcut(tr("CTRL+D"));
|
||||
exitAct->setStatusTip(tr("Exit the application"));
|
||||
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
|
||||
|
||||
//Help actions
|
||||
aboutAct = new QAction(tr("&About"), this);
|
||||
aboutAct->setShortcut(tr("CTRL+A"));
|
||||
aboutAct->setStatusTip(tr("About application"));
|
||||
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
|
||||
}
|
||||
|
||||
void MainWindow::createMenus()
|
||||
{
|
||||
fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
fileMenu->addAction(exitAct);
|
||||
|
||||
helpMenu = menuBar()->addMenu(tr("&Help"));
|
||||
helpMenu->addAction(aboutAct);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file MainWindow.h
|
||||
* @brief Application's Main Window.
|
||||
* @see MainWindow
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
|
||||
#ifndef MAINWINDOW_H_
|
||||
#define MAINWINDOW_H_
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class QMenu;
|
||||
class QAction;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QMenu *fileMenu;
|
||||
QAction *exitAct;
|
||||
QMenu *helpMenu;
|
||||
QAction *aboutAct;
|
||||
|
||||
private:
|
||||
void createMenus();
|
||||
void createActions();
|
||||
|
||||
private slots:
|
||||
void about();
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
};
|
||||
|
||||
#endif /*MAINWINDOW_H_*/
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @file MessageWindow.cpp
|
||||
* @brief MessageWindow Implementation.
|
||||
* @see MessageWindow.h
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "MessageWindow.h"
|
||||
#include <QMessageBox>
|
||||
#include <QCoreApplication>
|
||||
#include <QMutexLocker>
|
||||
|
||||
const char *MessageWindow::WINDOW_TITLE = "Message Window";
|
||||
MessageWindow *MessageWindow::MsgHandler = NULL;
|
||||
|
||||
MessageWindow::MessageWindow(QWidget *parent, Qt::WindowFlags flags)
|
||||
: QDockWidget(parent, flags),
|
||||
msgTextEdit(this)
|
||||
{
|
||||
setWindowTitle(tr(WINDOW_TITLE));
|
||||
msgTextEdit.setReadOnly(true);
|
||||
setWidget(&msgTextEdit);
|
||||
|
||||
MessageWindow::MsgHandler = this;
|
||||
}
|
||||
|
||||
//static
|
||||
QString MessageWindow::QtMsgToQString(QtMsgType type, const char *msg)
|
||||
{
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
return QLatin1String("Debug: ")+QLatin1String(msg);
|
||||
case QtWarningMsg:
|
||||
return QLatin1String("Warning: ")+QLatin1String(msg);
|
||||
case QtCriticalMsg:
|
||||
return QLatin1String("Critical: ")+QLatin1String(msg);
|
||||
case QtFatalMsg:
|
||||
return QLatin1String("Fatal: ")+QLatin1String(msg);
|
||||
default:
|
||||
return QLatin1String("Unrecognized message type: ")+QLatin1String(msg);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void MessageWindow::AppendMsgWrapper(QtMsgType type, const char *msg)
|
||||
{
|
||||
static QMutex mutex;
|
||||
QMutexLocker locker(&mutex);
|
||||
|
||||
if (MessageWindow::MsgHandler != NULL)
|
||||
return MessageWindow::MsgHandler->postMsgEvent(type, msg);
|
||||
else
|
||||
fprintf(stderr, "%s", MessageWindow::QtMsgToQString(type, msg).toLatin1().data());
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
void MessageWindow::AppendMsgWrapper(QtMsgType type, const QMessageLogContext & /*context*/, const QString &msg)
|
||||
{
|
||||
AppendMsgWrapper(type, msg.toLatin1().data());
|
||||
}
|
||||
#endif
|
||||
|
||||
void MessageWindow::customEvent(QEvent *event)
|
||||
{
|
||||
if (static_cast<MessageWindow::EventType>(event->type()) == MessageWindow::MessageEventType)
|
||||
msgTextEdit.append(dynamic_cast<MessageEvent *>(event)->msg);
|
||||
}
|
||||
|
||||
void MessageWindow::postMsgEvent(QtMsgType type, const char *msg)
|
||||
{
|
||||
QString qmsg = MessageWindow::QtMsgToQString(type, msg);
|
||||
switch (type) {
|
||||
case QtDebugMsg:
|
||||
break;
|
||||
case QtWarningMsg:
|
||||
qmsg.prepend(QLatin1String("<FONT color=\"#FF0000\">"));
|
||||
qmsg.append(QLatin1String("</FONT>"));
|
||||
break;
|
||||
case QtCriticalMsg:
|
||||
if (QMessageBox::critical(this, QLatin1String("Critical Error"), qmsg,
|
||||
QMessageBox::Ignore,
|
||||
QMessageBox::Abort,
|
||||
QMessageBox::NoButton) == QMessageBox::Abort)
|
||||
abort(); // core dump
|
||||
qmsg.prepend(QLatin1String("<B><FONT color=\"#FF0000\">"));
|
||||
qmsg.append(QLatin1String("</FONT></B>"));
|
||||
break;
|
||||
case QtFatalMsg:
|
||||
QMessageBox::critical(this, QLatin1String("Fatal Error"), qmsg, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
|
||||
abort(); // deliberately core dump
|
||||
}
|
||||
//it's impossible to change GUI directly from thread other than the main thread
|
||||
//so post message encapsulated by MessageEvent to the main thread's event queue
|
||||
QCoreApplication::postEvent(this, new MessageEvent(qmsg));
|
||||
}
|
||||
|
||||
MessageEvent::MessageEvent(QString &msg):
|
||||
QEvent(static_cast<QEvent::Type>(MessageWindow::MessageEventType))
|
||||
{
|
||||
this->msg = msg;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file MessageWindow.h
|
||||
* @brief Message Window.
|
||||
* @see MessageWindow
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
|
||||
#ifndef MESSAGEWINDOW_H_
|
||||
#define MESSAGEWINDOW_H_
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QEvent>
|
||||
|
||||
/**
|
||||
* Message Window. Handling errors and other messages.
|
||||
*/
|
||||
class MessageWindow: public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTextEdit msgTextEdit; ///< Main widget.
|
||||
static MessageWindow *MsgHandler; ///< Set in constructor.
|
||||
static const char *WINDOW_TITLE; ///< Window title.
|
||||
|
||||
private:
|
||||
static QString QtMsgToQString(QtMsgType type, const char *msg);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Handle custom events. MessageWindow hadles custom events listed in
|
||||
* EventType enum.
|
||||
*/
|
||||
virtual void customEvent(QEvent* event);
|
||||
|
||||
public:
|
||||
enum EventType {MessageEventType = QEvent::User}; ///< Custom event types.
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
* @param parent parent widget.
|
||||
* @param flags widget flags.
|
||||
*/
|
||||
MessageWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
||||
|
||||
/**
|
||||
* Append message wrapper. Since ISO forbids casting member functions
|
||||
* to C functions, wrapper is needed to use this class as QtMsgHandler.
|
||||
* This method is thread-safe but not reentrant.
|
||||
* @param type message type.
|
||||
* @param msg message string.
|
||||
*/
|
||||
static void AppendMsgWrapper(QtMsgType type, const char *msg);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
static void AppendMsgWrapper(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
#endif
|
||||
/**
|
||||
* Post message event to the main event loop. This function encapsulates
|
||||
* message into MessageEvent object and passes it to the main event loop.
|
||||
* @param type message type.
|
||||
* @param msg message string.
|
||||
*/
|
||||
void postMsgEvent(QtMsgType type, const char *msg);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Message Event. Custom event used by @ref MessageWindow to provide multi-threaded
|
||||
* access. Encapsulates message inside @a msg variable.
|
||||
*/
|
||||
class MessageEvent: public QEvent
|
||||
{
|
||||
public:
|
||||
QString msg; ///< Message string.
|
||||
|
||||
/**
|
||||
* Contructor.
|
||||
* @param msg message to post.
|
||||
*/
|
||||
MessageEvent(QString &msg);
|
||||
};
|
||||
|
||||
#endif /*MESSAGEWINDOW_H_*/
|
||||
@@ -0,0 +1,128 @@
|
||||
/* QespTest.cpp
|
||||
**************************************/
|
||||
#include "QespTest.h"
|
||||
#include "qextserialport.h"
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
|
||||
|
||||
QespTest::QespTest(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
|
||||
{
|
||||
//modify the port settings on your own
|
||||
#ifdef Q_OS_UNIX
|
||||
port = new QextSerialPort(QLatin1String("/dev/ttyS0"), QextSerialPort::Polling);
|
||||
#else
|
||||
port = new QextSerialPort(QLatin1String("COM1"), QextSerialPort::Polling);
|
||||
#endif /*Q_OS_UNIX*/
|
||||
port->setBaudRate(BAUD19200);
|
||||
port->setFlowControl(FLOW_OFF);
|
||||
port->setParity(PAR_NONE);
|
||||
port->setDataBits(DATA_8);
|
||||
port->setStopBits(STOP_2);
|
||||
//set timeouts to 500 ms
|
||||
port->setTimeout(500);
|
||||
|
||||
message = new QLineEdit(this);
|
||||
|
||||
// transmit receive
|
||||
QPushButton *transmitButton = new QPushButton(tr("Transmit"));
|
||||
connect(transmitButton, SIGNAL(clicked()), SLOT(transmitMsg()));
|
||||
QPushButton *receiveButton = new QPushButton(tr("Receive"));
|
||||
connect(receiveButton, SIGNAL(clicked()), SLOT(receiveMsg()));
|
||||
QHBoxLayout *trLayout = new QHBoxLayout;
|
||||
trLayout->addWidget(transmitButton);
|
||||
trLayout->addWidget(receiveButton);
|
||||
|
||||
//CR LF
|
||||
QPushButton *CRButton = new QPushButton(tr("CR"));
|
||||
connect(CRButton, SIGNAL(clicked()), SLOT(appendCR()));
|
||||
QPushButton *LFButton = new QPushButton(tr("LF"));
|
||||
connect(LFButton, SIGNAL(clicked()), SLOT(appendLF()));
|
||||
QHBoxLayout *crlfLayout = new QHBoxLayout;
|
||||
crlfLayout->addWidget(CRButton);
|
||||
crlfLayout->addWidget(LFButton);
|
||||
|
||||
//open close
|
||||
QPushButton *openButton = new QPushButton(tr("Open"));
|
||||
connect(openButton, SIGNAL(clicked()), SLOT(openPort()));
|
||||
QPushButton *closeButton = new QPushButton(tr("Close"));
|
||||
connect(closeButton, SIGNAL(clicked()), SLOT(closePort()));
|
||||
QHBoxLayout *ocLayout = new QHBoxLayout;
|
||||
ocLayout->addWidget(openButton);
|
||||
ocLayout->addWidget(closeButton);
|
||||
|
||||
received_msg = new QTextEdit();
|
||||
|
||||
QVBoxLayout *myVBox = new QVBoxLayout;
|
||||
myVBox->addWidget(message);
|
||||
myVBox->addLayout(crlfLayout);
|
||||
myVBox->addLayout(trLayout);
|
||||
myVBox->addLayout(ocLayout);
|
||||
myVBox->addWidget(received_msg);
|
||||
setLayout(myVBox);
|
||||
|
||||
qDebug("isOpen : %d", port->isOpen());
|
||||
}
|
||||
|
||||
QespTest::~QespTest()
|
||||
{
|
||||
delete port;
|
||||
port = NULL;
|
||||
}
|
||||
|
||||
void QespTest::transmitMsg()
|
||||
{
|
||||
int i = port->write(message->text().toLatin1());
|
||||
qDebug("trasmitted : %d", i);
|
||||
}
|
||||
|
||||
void QespTest::receiveMsg()
|
||||
{
|
||||
char buff[1024];
|
||||
int numBytes;
|
||||
|
||||
numBytes = port->bytesAvailable();
|
||||
if(numBytes > 1024)
|
||||
numBytes = 1024;
|
||||
|
||||
int i = port->read(buff, numBytes);
|
||||
if (i != -1)
|
||||
buff[i] = '\0';
|
||||
else
|
||||
buff[0] = '\0';
|
||||
QString msg = QLatin1String(buff);
|
||||
|
||||
received_msg->append(msg);
|
||||
received_msg->ensureCursorVisible();
|
||||
qDebug("bytes available: %d", numBytes);
|
||||
qDebug("received: %d", i);
|
||||
}
|
||||
|
||||
|
||||
void QespTest::appendCR()
|
||||
{
|
||||
message->insert(QLatin1String("\x0D"));
|
||||
}
|
||||
|
||||
void QespTest::appendLF()
|
||||
{
|
||||
message->insert(QLatin1String("\x0A"));
|
||||
}
|
||||
|
||||
void QespTest::closePort()
|
||||
{
|
||||
port->close();
|
||||
qDebug("is open: %d", port->isOpen());
|
||||
}
|
||||
|
||||
void QespTest::openPort()
|
||||
{
|
||||
port->open(QIODevice::ReadWrite | QIODevice::Unbuffered);
|
||||
qDebug("is open: %d", port->isOpen());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* qesptest.h
|
||||
**************************************/
|
||||
#ifndef _QESPTEST_H_
|
||||
#define _QESPTEST_H_
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
class QextSerialPort;
|
||||
class QSpinBox;
|
||||
|
||||
class QespTest : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QespTest(QWidget *parent=0);
|
||||
|
||||
virtual ~QespTest();
|
||||
|
||||
private:
|
||||
QLineEdit *message;
|
||||
QSpinBox *delaySpinBox;
|
||||
QTextEdit *received_msg;
|
||||
QextSerialPort *port;
|
||||
|
||||
private slots:
|
||||
void transmitMsg();
|
||||
void receiveMsg();
|
||||
void appendCR();
|
||||
void appendLF();
|
||||
void closePort();
|
||||
void openPort();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
This is simple application using QextSerialPort library.
|
||||
|
||||
Port settings are in QespTest constructor (QespTest.cpp)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Main file.
|
||||
* @author Micha? Policht
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include "MainWindow.h"
|
||||
#include "MessageWindow.h"
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
//! [0]
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
//redirect debug messages to the MessageWindow dialog
|
||||
qInstallMsgHandler(MessageWindow::AppendMsgWrapper);
|
||||
#else
|
||||
qInstallMessageHandler(MessageWindow::AppendMsgWrapper);
|
||||
#endif
|
||||
//! [0]
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
TEMPLATE = app
|
||||
DEPENDPATH += .
|
||||
QT += core gui
|
||||
contains(QT_VERSION, ^5\\..*\\..*): QT += widgets
|
||||
HEADERS += MainWindow.h \
|
||||
MessageWindow.h \
|
||||
QespTest.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
MainWindow.cpp \
|
||||
MessageWindow.cpp \
|
||||
QespTest.cpp
|
||||
|
||||
include(../../src/qextserialport.pri)
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -0,0 +1,179 @@
|
||||
#include "qextserialport.h"
|
||||
#include "qextserialenumerator.h"
|
||||
#include "dialog.h"
|
||||
#include "ui_dialog.h"
|
||||
#include <QtCore>
|
||||
|
||||
Dialog::Dialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::Dialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
//! [0]
|
||||
foreach (QextPortInfo info, QextSerialEnumerator::getPorts())
|
||||
ui->portBox->addItem(info.portName);
|
||||
//make sure user can input their own port name!
|
||||
ui->portBox->setEditable(true);
|
||||
|
||||
ui->baudRateBox->addItem("1200", BAUD1200);
|
||||
ui->baudRateBox->addItem("2400", BAUD2400);
|
||||
ui->baudRateBox->addItem("4800", BAUD4800);
|
||||
ui->baudRateBox->addItem("9600", BAUD9600);
|
||||
ui->baudRateBox->addItem("19200", BAUD19200);
|
||||
ui->baudRateBox->setCurrentIndex(3);
|
||||
|
||||
ui->parityBox->addItem("NONE", PAR_NONE);
|
||||
ui->parityBox->addItem("ODD", PAR_ODD);
|
||||
ui->parityBox->addItem("EVEN", PAR_EVEN);
|
||||
|
||||
ui->dataBitsBox->addItem("5", DATA_5);
|
||||
ui->dataBitsBox->addItem("6", DATA_6);
|
||||
ui->dataBitsBox->addItem("7", DATA_7);
|
||||
ui->dataBitsBox->addItem("8", DATA_8);
|
||||
ui->dataBitsBox->setCurrentIndex(3);
|
||||
|
||||
ui->stopBitsBox->addItem("1", STOP_1);
|
||||
ui->stopBitsBox->addItem("2", STOP_2);
|
||||
|
||||
ui->queryModeBox->addItem("Polling", QextSerialPort::Polling);
|
||||
ui->queryModeBox->addItem("EventDriven", QextSerialPort::EventDriven);
|
||||
//! [0]
|
||||
|
||||
ui->led->turnOff();
|
||||
|
||||
timer = new QTimer(this);
|
||||
timer->setInterval(40);
|
||||
//! [1]
|
||||
PortSettings settings = {BAUD9600, DATA_8, PAR_NONE, STOP_1, FLOW_OFF, 10};
|
||||
port = new QextSerialPort(ui->portBox->currentText(), settings, QextSerialPort::Polling);
|
||||
//! [1]
|
||||
|
||||
enumerator = new QextSerialEnumerator(this);
|
||||
enumerator->setUpNotifications();
|
||||
|
||||
connect(ui->baudRateBox, SIGNAL(currentIndexChanged(int)), SLOT(onBaudRateChanged(int)));
|
||||
connect(ui->parityBox, SIGNAL(currentIndexChanged(int)), SLOT(onParityChanged(int)));
|
||||
connect(ui->dataBitsBox, SIGNAL(currentIndexChanged(int)), SLOT(onDataBitsChanged(int)));
|
||||
connect(ui->stopBitsBox, SIGNAL(currentIndexChanged(int)), SLOT(onStopBitsChanged(int)));
|
||||
connect(ui->queryModeBox, SIGNAL(currentIndexChanged(int)), SLOT(onQueryModeChanged(int)));
|
||||
connect(ui->timeoutBox, SIGNAL(valueChanged(int)), SLOT(onTimeoutChanged(int)));
|
||||
connect(ui->portBox, SIGNAL(editTextChanged(QString)), SLOT(onPortNameChanged(QString)));
|
||||
connect(ui->openCloseButton, SIGNAL(clicked()), SLOT(onOpenCloseButtonClicked()));
|
||||
connect(ui->sendButton, SIGNAL(clicked()), SLOT(onSendButtonClicked()));
|
||||
connect(timer, SIGNAL(timeout()), SLOT(onReadyRead()));
|
||||
connect(port, SIGNAL(readyRead()), SLOT(onReadyRead()));
|
||||
|
||||
connect(enumerator, SIGNAL(deviceDiscovered(QextPortInfo)), SLOT(onPortAddedOrRemoved()));
|
||||
connect(enumerator, SIGNAL(deviceRemoved(QextPortInfo)), SLOT(onPortAddedOrRemoved()));
|
||||
|
||||
setWindowTitle(tr("QextSerialPort Demo"));
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
delete ui;
|
||||
delete port;
|
||||
}
|
||||
|
||||
void Dialog::changeEvent(QEvent *e)
|
||||
{
|
||||
QDialog::changeEvent(e);
|
||||
switch (e->type()) {
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::onPortNameChanged(const QString & /*name*/)
|
||||
{
|
||||
if (port->isOpen()) {
|
||||
port->close();
|
||||
ui->led->turnOff();
|
||||
}
|
||||
}
|
||||
//! [2]
|
||||
void Dialog::onBaudRateChanged(int idx)
|
||||
{
|
||||
port->setBaudRate((BaudRateType)ui->baudRateBox->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void Dialog::onParityChanged(int idx)
|
||||
{
|
||||
port->setParity((ParityType)ui->parityBox->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void Dialog::onDataBitsChanged(int idx)
|
||||
{
|
||||
port->setDataBits((DataBitsType)ui->dataBitsBox->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void Dialog::onStopBitsChanged(int idx)
|
||||
{
|
||||
port->setStopBits((StopBitsType)ui->stopBitsBox->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void Dialog::onQueryModeChanged(int idx)
|
||||
{
|
||||
port->setQueryMode((QextSerialPort::QueryMode)ui->queryModeBox->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void Dialog::onTimeoutChanged(int val)
|
||||
{
|
||||
port->setTimeout(val);
|
||||
}
|
||||
//! [2]
|
||||
//! [3]
|
||||
void Dialog::onOpenCloseButtonClicked()
|
||||
{
|
||||
if (!port->isOpen()) {
|
||||
port->setPortName(ui->portBox->currentText());
|
||||
port->open(QIODevice::ReadWrite);
|
||||
}
|
||||
else {
|
||||
port->close();
|
||||
}
|
||||
|
||||
//If using polling mode, we need a QTimer
|
||||
if (port->isOpen() && port->queryMode() == QextSerialPort::Polling)
|
||||
timer->start();
|
||||
else
|
||||
timer->stop();
|
||||
|
||||
//update led's status
|
||||
ui->led->turnOn(port->isOpen());
|
||||
}
|
||||
//! [3]
|
||||
//! [4]
|
||||
void Dialog::onSendButtonClicked()
|
||||
{
|
||||
if (port->isOpen() && !ui->sendEdit->toPlainText().isEmpty())
|
||||
port->write(ui->sendEdit->toPlainText().toLatin1());
|
||||
}
|
||||
|
||||
void Dialog::onReadyRead()
|
||||
{
|
||||
if (port->bytesAvailable()) {
|
||||
ui->recvEdit->moveCursor(QTextCursor::End);
|
||||
ui->recvEdit->insertPlainText(QString::fromLatin1(port->readAll()));
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::onPortAddedOrRemoved()
|
||||
{
|
||||
QString current = ui->portBox->currentText();
|
||||
|
||||
ui->portBox->blockSignals(true);
|
||||
ui->portBox->clear();
|
||||
foreach (QextPortInfo info, QextSerialEnumerator::getPorts())
|
||||
ui->portBox->addItem(info.portName);
|
||||
|
||||
ui->portBox->setCurrentIndex(ui->portBox->findText(current));
|
||||
|
||||
ui->portBox->blockSignals(false);
|
||||
}
|
||||
|
||||
//! [4]
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef DIALOG_H
|
||||
#define DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class Dialog;
|
||||
}
|
||||
class QTimer;
|
||||
class QextSerialPort;
|
||||
class QextSerialEnumerator;
|
||||
|
||||
class Dialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Dialog(QWidget *parent = 0);
|
||||
~Dialog();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPortNameChanged(const QString &name);
|
||||
void onBaudRateChanged(int idx);
|
||||
void onParityChanged(int idx);
|
||||
void onDataBitsChanged(int idx);
|
||||
void onStopBitsChanged(int idx);
|
||||
void onQueryModeChanged(int idx);
|
||||
void onTimeoutChanged(int val);
|
||||
void onOpenCloseButtonClicked();
|
||||
void onSendButtonClicked();
|
||||
void onReadyRead();
|
||||
|
||||
void onPortAddedOrRemoved();
|
||||
|
||||
private:
|
||||
Ui::Dialog *ui;
|
||||
QTimer *timer;
|
||||
QextSerialPort *port;
|
||||
QextSerialEnumerator *enumerator;
|
||||
};
|
||||
|
||||
#endif // DIALOG_H
|
||||
@@ -0,0 +1,191 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>604</width>
|
||||
<height>485</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="3,1">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="recvEdit">
|
||||
<property name="maximumBlockCount">
|
||||
<number>800</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="sendEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="portBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>BaudRate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="baudRateBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>DataBits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="dataBitsBox"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Parity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="parityBox"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>StopBits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="stopBitsBox"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>QueryMode:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="queryModeBox"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Timeout:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="timeoutBox">
|
||||
<property name="suffix">
|
||||
<string> ms</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="HLed" name="led" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="openCloseButton">
|
||||
<property name="text">
|
||||
<string>Open/Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="sendButton">
|
||||
<property name="text">
|
||||
<string>Send</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>HLed</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>hled.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <QtGui>
|
||||
#include "hled.h"
|
||||
|
||||
struct HLed::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: darkerFactor(300), color(Qt::green), isOn(true)
|
||||
{ }
|
||||
|
||||
int darkerFactor;
|
||||
QColor color;
|
||||
bool isOn;
|
||||
};
|
||||
|
||||
HLed::HLed(QWidget *parent)
|
||||
:QWidget(parent), m_d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
HLed::~HLed()
|
||||
{
|
||||
delete m_d;
|
||||
}
|
||||
|
||||
QColor HLed::color() const
|
||||
{
|
||||
return m_d->color;
|
||||
}
|
||||
|
||||
void HLed::setColor(const QColor &color)
|
||||
{
|
||||
if (m_d->color == color)
|
||||
return;
|
||||
update();
|
||||
}
|
||||
|
||||
QSize HLed::sizeHint() const
|
||||
{
|
||||
return QSize(20, 20);
|
||||
}
|
||||
|
||||
QSize HLed::minimumSizeHint() const
|
||||
{
|
||||
return QSize(16, 16);
|
||||
}
|
||||
|
||||
void HLed::toggle()
|
||||
{
|
||||
m_d->isOn = !m_d->isOn;
|
||||
update();
|
||||
}
|
||||
|
||||
void HLed::turnOn(bool on)
|
||||
{
|
||||
m_d->isOn = on;
|
||||
update();
|
||||
}
|
||||
|
||||
void HLed::turnOff(bool off)
|
||||
{
|
||||
turnOn(!off);
|
||||
}
|
||||
|
||||
void HLed::paintEvent(QPaintEvent * /*event*/)
|
||||
{
|
||||
int width = ledWidth();
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QColor color = m_d->isOn ? m_d->color
|
||||
: m_d->color.darker(m_d->darkerFactor);
|
||||
|
||||
QBrush brush;
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(color);
|
||||
painter.setBrush(brush);
|
||||
// draw plain
|
||||
painter.drawEllipse(1, 1, width-1, width-1);
|
||||
|
||||
QPen pen;
|
||||
pen.setWidth(2);
|
||||
|
||||
int pos = width / 5 + 1;
|
||||
int lightWidth = width * 2 / 3;
|
||||
int lightQuote = 130 * 2 / (lightWidth ? lightWidth : 1) + 100;
|
||||
|
||||
// draw bright spot
|
||||
while (lightWidth) {
|
||||
color = color.lighter(lightQuote);
|
||||
pen.setColor(color);
|
||||
painter.setPen(pen);
|
||||
painter.drawEllipse(pos, pos, lightWidth, lightWidth);
|
||||
lightWidth--;
|
||||
|
||||
if (!lightWidth)
|
||||
break;
|
||||
|
||||
painter.drawEllipse(pos, pos, lightWidth, lightWidth);
|
||||
lightWidth--;
|
||||
|
||||
if (!lightWidth)
|
||||
break;
|
||||
|
||||
painter.drawEllipse(pos, pos, lightWidth, lightWidth);
|
||||
pos++;
|
||||
lightWidth--;
|
||||
}
|
||||
|
||||
//draw border
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
|
||||
int angle = -720;
|
||||
color = palette().color(QPalette::Light);
|
||||
|
||||
for (int arc=120; arc<2880; arc+=240) {
|
||||
pen.setColor(color);
|
||||
painter.setPen(pen);
|
||||
int w = width - pen.width()/2;
|
||||
painter.drawArc(pen.width()/2, pen.width()/2, w, w, angle+arc, 240);
|
||||
painter.drawArc(pen.width()/2, pen.width()/2, w, w, angle-arc, 240);
|
||||
color = color.darker(110);
|
||||
}
|
||||
}
|
||||
|
||||
int HLed::ledWidth() const
|
||||
{
|
||||
int width = qMin(this->width(), this->height());
|
||||
width -= 2;
|
||||
return width > 0 ? width : 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef HLED_H
|
||||
#define HLED_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QColor;
|
||||
|
||||
class HLed : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HLed(QWidget *parent = 0);
|
||||
~HLed();
|
||||
|
||||
QColor color() const;
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
||||
public slots:
|
||||
void setColor(const QColor &color);
|
||||
void toggle();
|
||||
void turnOn(bool on=true);
|
||||
void turnOff(bool off=true);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *);
|
||||
int ledWidth() const;
|
||||
|
||||
private:
|
||||
struct Private;
|
||||
Private * const m_d;
|
||||
};
|
||||
|
||||
#endif // HLED_H
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <QApplication>
|
||||
#include "dialog.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
Dialog w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2011-11-06T21:37:41
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
contains(QT_VERSION, ^5\\..*\\..*): QT += widgets
|
||||
|
||||
TARGET = uartassistant
|
||||
TEMPLATE = app
|
||||
|
||||
include(../../src/qextserialport.pri)
|
||||
|
||||
SOURCES += main.cpp\
|
||||
dialog.cpp\
|
||||
hled.cpp
|
||||
|
||||
HEADERS += dialog.h \
|
||||
hled.h
|
||||
|
||||
FORMS += dialog.ui
|
||||
@@ -0,0 +1,24 @@
|
||||
defineReplace(qextLibraryName) {
|
||||
unset(LIBRARY_NAME)
|
||||
LIBRARY_NAME = \$\$1
|
||||
greaterThan(QT_MAJOR_VERSION, 4):LIBRARY_NAME ~= s,^Qt,Qt\$\$QT_MAJOR_VERSION,
|
||||
CONFIG(debug, debug|release) {
|
||||
!debug_and_release|build_pass {
|
||||
mac:LIBRARY_NAME = \$\${LIBRARY_NAME}_debug
|
||||
else:win32:LIBRARY_NAME = \$\${LIBRARY_NAME}d
|
||||
}
|
||||
}
|
||||
return(\$\$LIBRARY_NAME)
|
||||
}
|
||||
|
||||
!!IF qesp_mac_framework
|
||||
LIBS += -framework $$QESP_LIB_BASENAME
|
||||
INCLUDEPATH += $$[QT_INSTALL_LIBS]/$${QESP_LIB_BASENAME}.framework/Headers
|
||||
!!ELSE
|
||||
LIBS += -l\$\$qextLibraryName($$QESP_LIB_BASENAME)
|
||||
INCLUDEPATH += $$[QT_INSTALL_HEADERS]/QtExtSerialPort
|
||||
!!ENDIF
|
||||
|
||||
!!IF !qesp_static
|
||||
DEFINES += QEXTSERIALPORT_USING_SHARED
|
||||
!!ENDIF
|
||||
@@ -0,0 +1,96 @@
|
||||
############################### *User Config* ###############################
|
||||
|
||||
# Uncomment following line if you want to build a static library
|
||||
# CONFIG += qesp_static
|
||||
|
||||
# Uncomment following line if you want to build framework for mac
|
||||
# macx:CONFIG += qesp_mac_framework
|
||||
|
||||
# Uncomment following line if you want to enable udev for linux
|
||||
# linux*:CONFIG += qesp_linux_udev
|
||||
|
||||
# Note: you can create a ".qmake.cache" file, then copy these lines to it.
|
||||
# If so, you can avoid to change this project file.
|
||||
############################### *User Config* ###############################
|
||||
|
||||
defineReplace(qextLibraryName) {
|
||||
unset(LIBRARY_NAME)
|
||||
LIBRARY_NAME = $$1
|
||||
macx:qesp_mac_framework {
|
||||
QMAKE_FRAMEWORK_BUNDLE_NAME = $$LIBRARY_NAME
|
||||
export(QMAKE_FRAMEWORK_BUNDLE_NAME)
|
||||
} else {
|
||||
greaterThan(QT_MAJOR_VERSION, 4):LIBRARY_NAME ~= s,^Qt,Qt$$QT_MAJOR_VERSION,
|
||||
}
|
||||
CONFIG(debug, debug|release) {
|
||||
!debug_and_release|build_pass {
|
||||
mac:LIBRARY_NAME = $${LIBRARY_NAME}_debug
|
||||
else:win32:LIBRARY_NAME = $${LIBRARY_NAME}d
|
||||
}
|
||||
}
|
||||
return($$LIBRARY_NAME)
|
||||
}
|
||||
|
||||
TEMPLATE=lib
|
||||
include(src/qextserialport.pri)
|
||||
|
||||
#create_prl is needed, otherwise, MinGW can't found libqextserialport1.a
|
||||
CONFIG += create_prl
|
||||
|
||||
#mac framework is designed for shared library
|
||||
macx:qesp_mac_framework:qesp_static: CONFIG -= qesp_static
|
||||
!macx:qesp_mac_framework:CONFIG -= qesp_mac_framework
|
||||
|
||||
qesp_static {
|
||||
CONFIG += static
|
||||
} else {
|
||||
CONFIG += shared
|
||||
macx:!qesp_mac_framework:CONFIG += absolute_library_soname
|
||||
DEFINES += QEXTSERIALPORT_BUILD_SHARED
|
||||
}
|
||||
|
||||
#Creare lib bundle for mac
|
||||
macx:qesp_mac_framework {
|
||||
CONFIG += lib_bundle
|
||||
FRAMEWORK_HEADERS.files = $$PUBLIC_HEADERS
|
||||
FRAMEWORK_HEADERS.path = Headers
|
||||
QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS
|
||||
}
|
||||
|
||||
win32|mac:!wince*:!win32-msvc:!macx-xcode:CONFIG += debug_and_release build_all
|
||||
|
||||
#For non-windows system, only depends on QtCore module
|
||||
unix:QT = core
|
||||
else:QT = core gui
|
||||
|
||||
#generate proper library name
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
QESP_LIB_BASENAME = QtExtSerialPort
|
||||
} else {
|
||||
QESP_LIB_BASENAME = qextserialport
|
||||
}
|
||||
TARGET = $$qextLibraryName($$QESP_LIB_BASENAME)
|
||||
VERSION = 1.2.0
|
||||
|
||||
# generate feature file by qmake based on this *.in file.
|
||||
QMAKE_SUBSTITUTES += extserialport.prf.in
|
||||
OTHER_FILES += extserialport.prf.in
|
||||
|
||||
# for make docs
|
||||
include(doc/doc.pri)
|
||||
|
||||
# for make install
|
||||
win32:!qesp_static {
|
||||
dlltarget.path = $$[QT_INSTALL_BINS]
|
||||
INSTALLS += dlltarget
|
||||
}
|
||||
!macx|!qesp_mac_framework {
|
||||
headers.files = $$PUBLIC_HEADERS
|
||||
headers.path = $$[QT_INSTALL_HEADERS]/QtExtSerialPort
|
||||
INSTALLS += headers
|
||||
}
|
||||
target.path = $$[QT_INSTALL_LIBS]
|
||||
|
||||
features.files = extserialport.prf
|
||||
features.path = $$[QMAKE_MKSPECS]/features
|
||||
INSTALLS += target features
|
||||
@@ -0,0 +1,2 @@
|
||||
[.ShellClassInfo]
|
||||
IconResource=C:\Users\Corwin\AppData\Roaming\Insync\App\res\shared-folder-vista-7.ico,0
|
||||
@@ -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)
|
||||
{
|
||||
platformSpecificInit();
|
||||
}
|
||||
|
||||
QextSerialEnumeratorPrivate::~QextSerialEnumeratorPrivate()
|
||||
{
|
||||
platformSpecificDestruct();
|
||||
}
|
||||
|
||||
/*!
|
||||
\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"
|
||||
@@ -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_*/
|
||||
@@ -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::platformSpecificInit()
|
||||
{
|
||||
#ifndef QESP_NO_UDEV
|
||||
monitor = NULL;
|
||||
notifierFd = -1;
|
||||
notifier = NULL;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
qCritical() << "Unable to initialize udev notifications";
|
||||
#endif
|
||||
}
|
||||
|
||||
void QextSerialEnumeratorPrivate::platformSpecificDestruct()
|
||||
{
|
||||
#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));
|
||||
udev_device_unref(dev);
|
||||
|
||||
if (action == QLatin1String("add"))
|
||||
Q_EMIT q->deviceDiscovered(pi);
|
||||
else if (action == QLatin1String("remove"))
|
||||
Q_EMIT q->deviceRemoved(pi);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -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::platformSpecificInit()
|
||||
{
|
||||
}
|
||||
|
||||
void QextSerialEnumeratorPrivate::platformSpecificDestruct()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/****************************************************************************
|
||||
** 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_OS_WIN
|
||||
// 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
|
||||
# ifdef __MINGW32__
|
||||
# define _WIN32_WINNT 0x0500
|
||||
# define _WIN32_WINDOWS 0x0500
|
||||
# define WINVER 0x0500
|
||||
# endif
|
||||
# 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 platformSpecificInit();
|
||||
void platformSpecificDestruct();
|
||||
|
||||
static QList<QextPortInfo> getPorts_sys();
|
||||
bool setUpNotifications_sys(bool setup);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
LRESULT onDeviceChanged(WPARAM wParam, LPARAM lParam);
|
||||
bool matchAndDispatchChangedDevice(const QString &deviceID, const GUID &guid, WPARAM wParam);
|
||||
# ifdef QT_GUI_LIB
|
||||
QextSerialRegistrationWidget *notificationWidget;
|
||||
# endif
|
||||
#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_
|
||||
@@ -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::platformSpecificInit()
|
||||
{
|
||||
}
|
||||
|
||||
void QextSerialEnumeratorPrivate::platformSpecificDestruct()
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/****************************************************************************
|
||||
** 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 <objbase.h>
|
||||
#include <initguid.h>
|
||||
#include <setupapi.h>
|
||||
#include <dbt.h>
|
||||
#include "qextserialport.h"
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
#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::platformSpecificInit()
|
||||
{
|
||||
#ifdef QT_GUI_LIB
|
||||
notificationWidget = 0;
|
||||
#endif // QT_GUI_LIB
|
||||
}
|
||||
|
||||
/*!
|
||||
default
|
||||
*/
|
||||
void QextSerialEnumeratorPrivate::platformSpecificDestruct()
|
||||
{
|
||||
#ifdef QT_GUI_LIB
|
||||
if (notificationWidget)
|
||||
delete notificationWidget;
|
||||
#endif
|
||||
}
|
||||
|
||||
// see http://msdn.microsoft.com/en-us/library/windows/hardware/ff553426(v=vs.85).aspx
|
||||
// for list of GUID classes
|
||||
const GUID deviceClassGuids[] =
|
||||
{
|
||||
// Ports (COM & LPT ports), Class = Ports
|
||||
{0x4D36E978, 0xE325, 0x11CE, {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}},
|
||||
// Modem, Class = Modem
|
||||
{0x4D36E96D, 0xE325, 0x11CE, {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}},
|
||||
// Bluetooth Devices, Class = Bluetooth
|
||||
{0xE0CBF06C, 0xCD8B, 0x4647, {0xBB, 0x8A, 0x26, 0x3B, 0x43, 0xF0, 0xF9, 0x74}},
|
||||
// Added by Arne Kristian Jansen, for use with com0com virtual ports (See Issue 54)
|
||||
{0xDF799E12, 0x3C56, 0x421B, {0xB2, 0x98, 0xB6, 0xD3, 0x64, 0x2B, 0xC8, 0x78}}
|
||||
};
|
||||
|
||||
/* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */
|
||||
#ifdef UNICODE
|
||||
#define QStringToTCHAR(x) (wchar_t *) x.utf16()
|
||||
#define PQStringToTCHAR(x) (wchar_t *) x->utf16()
|
||||
#define TCHARToQString(x) QString::fromUtf16((ushort *)(x))
|
||||
#define TCHARToQStringN(x,y) QString::fromUtf16((ushort *)(x),(y))
|
||||
#else
|
||||
#define QStringToTCHAR(x) x.local8Bit().constData()
|
||||
#define PQStringToTCHAR(x) x->local8Bit().constData()
|
||||
#define TCHARToQString(x) QString::fromLocal8Bit((char *)(x))
|
||||
#define TCHARToQStringN(x,y) QString::fromLocal8Bit((char *)(x),(y))
|
||||
#endif /*UNICODE*/
|
||||
|
||||
/*!
|
||||
\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;
|
||||
::RegQueryValueEx(key, property, NULL, NULL, NULL, &size);
|
||||
BYTE *buff = new BYTE[size];
|
||||
QString result;
|
||||
if (::RegQueryValueEx(key, property, NULL, &type, buff, &size) == ERROR_SUCCESS)
|
||||
result = TCHARToQString(buff);
|
||||
::RegCloseKey(key);
|
||||
delete [] buff;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
Get specific property from registry.
|
||||
\a devInfo pointer to the device information set that contains the interface
|
||||
and its underlying device. Returned by SetupDiGetClassDevs() function.
|
||||
\a devData 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 getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property)
|
||||
{
|
||||
DWORD buffSize = 0;
|
||||
::SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, &buffSize);
|
||||
BYTE *buff = new BYTE[buffSize];
|
||||
::SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL);
|
||||
QString result = TCHARToQString(buff);
|
||||
delete [] buff;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
static bool getDeviceDetailsWin(QextPortInfo *portInfo, HDEVINFO devInfo, PSP_DEVINFO_DATA devData
|
||||
, WPARAM wParam = DBT_DEVICEARRIVAL)
|
||||
{
|
||||
portInfo->friendName = getDeviceProperty(devInfo, devData, SPDRP_FRIENDLYNAME);
|
||||
if (wParam == DBT_DEVICEARRIVAL)
|
||||
portInfo->physName = getDeviceProperty(devInfo, devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
|
||||
portInfo->enumName = getDeviceProperty(devInfo, devData, SPDRP_ENUMERATOR_NAME);
|
||||
QString hardwareIDs = getDeviceProperty(devInfo, devData, SPDRP_HARDWAREID);
|
||||
HKEY devKey = ::SetupDiOpenDevRegKey(devInfo, devData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||
portInfo->portName = getRegKeyValue(devKey, TEXT("PortName"));
|
||||
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 enumerateDevicesWin(const GUID &guid, QList<QextPortInfo> *infoList)
|
||||
{
|
||||
HDEVINFO devInfo;
|
||||
if ((devInfo = ::SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT)) != INVALID_HANDLE_VALUE) {
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
for(int i = 0; ::SetupDiEnumDeviceInfo(devInfo, i, &devInfoData); i++) {
|
||||
QextPortInfo info;
|
||||
info.productID = info.vendorID = 0;
|
||||
getDeviceDetailsWin(&info, devInfo, &devInfoData);
|
||||
if (!info.portName.startsWith(QLatin1String("LPT"), Qt::CaseInsensitive))
|
||||
infoList->append(info);
|
||||
}
|
||||
::SetupDiDestroyDeviceInfoList(devInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
const int count = sizeof(deviceClassGuids)/sizeof(deviceClassGuids[0]);
|
||||
for (int i=0; i<count; ++i)
|
||||
enumerateDevicesWin(deviceClassGuids[i], &ports);
|
||||
qSort(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
|
||||
}
|
||||
|
||||
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 = TCHARToQString(pDevInf->dbcc_name).toUpper().replace(QLatin1String("#"), QLatin1String("\\"));
|
||||
|
||||
const int count = sizeof(deviceClassGuids)/sizeof(deviceClassGuids[0]);
|
||||
for (int i=0; i<count; ++i) {
|
||||
if (matchAndDispatchChangedDevice(deviceID, deviceClassGuids[i], wParam))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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_ALLCLASSES;
|
||||
HDEVINFO devInfo;
|
||||
if ((devInfo = SetupDiGetClassDevs(&guid,NULL,NULL,dwFlag)) != INVALID_HANDLE_VALUE) {
|
||||
SP_DEVINFO_DATA spDevInfoData;
|
||||
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
for(int i=0; SetupDiEnumDeviceInfo(devInfo, i, &spDevInfoData); i++) {
|
||||
DWORD nSize = 0;
|
||||
TCHAR buf[MAX_PATH];
|
||||
if (SetupDiGetDeviceInstanceId(devInfo, &spDevInfoData, buf, MAX_PATH, &nSize) &&
|
||||
deviceID.contains(TCHARToQString(buf))) { // we found a match
|
||||
rv = true;
|
||||
QextPortInfo info;
|
||||
info.productID = info.vendorID = 0;
|
||||
getDeviceDetailsWin(&info, devInfo, &spDevInfoData, wParam);
|
||||
if (wParam == DBT_DEVICEARRIVAL)
|
||||
Q_EMIT q->deviceDiscovered(info);
|
||||
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||
Q_EMIT q->deviceRemoved(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(devInfo);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
/****************************************************************************
|
||||
** 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_
|
||||
@@ -0,0 +1,460 @@
|
||||
/****************************************************************************
|
||||
** 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;
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
/****************************************************************************
|
||||
** 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;
|
||||
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