From ae8ffd0ccab0c03ffaf9985a7889d65177227f9e Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Sun, 2 Nov 2014 14:16:14 -0800 Subject: [PATCH] Switch Firmware Upgrade to qextserialport QSerialPort buffering too slow on Windows. --- libs/qextserialport/.gitignore | 47 + libs/qextserialport/ChangeLog | 267 +++++ libs/qextserialport/LICENSE | 94 ++ libs/qextserialport/README | 64 ++ libs/qextserialport/doc/doc.pri | 12 + .../doc/examples/enumerator.qdoc | 16 + .../doc/examples/images/uartassistant.png | Bin 0 -> 20753 bytes libs/qextserialport/doc/examples/qespta.qdoc | 7 + .../doc/examples/uartassistant.qdoc | 24 + libs/qextserialport/doc/index.qdoc | 199 ++++ .../doc/qextserialport.qdocconf | 53 + libs/qextserialport/doc/readme.txt | 35 + libs/qextserialport/doc/style/style.css | 137 +++ .../examples/enumerator/enumerator.pro | 6 + .../examples/enumerator/main.cpp | 31 + .../examples/event/PortListener.cpp | 43 + .../examples/event/PortListener.h | 26 + libs/qextserialport/examples/event/event.pro | 7 + libs/qextserialport/examples/event/main.cpp | 19 + libs/qextserialport/examples/examples.pro | 5 + .../examples/qespta/MainWindow.cpp | 61 + .../examples/qespta/MainWindow.h | 38 + .../examples/qespta/MessageWindow.cpp | 102 ++ .../examples/qespta/MessageWindow.h | 84 ++ .../examples/qespta/QespTest.cpp | 128 +++ .../qextserialport/examples/qespta/QespTest.h | 36 + libs/qextserialport/examples/qespta/README | 4 + libs/qextserialport/examples/qespta/main.cpp | 30 + .../qextserialport/examples/qespta/qespta.pro | 14 + .../examples/uartassistant/dialog.cpp | 179 +++ .../examples/uartassistant/dialog.h | 45 + .../examples/uartassistant/dialog.ui | 191 ++++ .../examples/uartassistant/hled.cpp | 133 +++ .../examples/uartassistant/hled.h | 34 + .../examples/uartassistant/main.cpp | 11 + .../examples/uartassistant/uartassistant.pro | 22 + libs/qextserialport/extserialport.prf.in | 24 + libs/qextserialport/qextserialport.pro | 96 ++ .../src/qextserialenumerator.cpp | 163 +++ .../qextserialport/src/qextserialenumerator.h | 72 ++ .../src/qextserialenumerator_linux.cpp | 210 ++++ .../src/qextserialenumerator_osx.cpp | 307 +++++ .../src/qextserialenumerator_p.h | 120 ++ .../src/qextserialenumerator_unix.cpp | 56 + .../src/qextserialenumerator_win.cpp | 318 ++++++ libs/qextserialport/src/qextserialport.cpp | 1011 +++++++++++++++++ libs/qextserialport/src/qextserialport.h | 240 ++++ libs/qextserialport/src/qextserialport.pri | 36 + .../src/qextserialport_global.h | 72 ++ libs/qextserialport/src/qextserialport_p.h | 251 ++++ .../src/qextserialport_unix.cpp | 460 ++++++++ .../qextserialport/src/qextserialport_win.cpp | 418 +++++++ qgroundcontrol.pro | 2 + src/ui/px4_configuration/PX4Bootloader.cc | 178 +-- src/ui/px4_configuration/PX4Bootloader.h | 34 +- .../px4_configuration/PX4FirmwareUpgrade.cc | 3 +- src/ui/px4_configuration/PX4FirmwareUpgrade.h | 3 +- .../PX4FirmwareUpgradeThread.cc | 6 +- .../PX4FirmwareUpgradeThread.h | 5 +- 59 files changed, 6186 insertions(+), 103 deletions(-) create mode 100644 libs/qextserialport/.gitignore create mode 100755 libs/qextserialport/ChangeLog create mode 100755 libs/qextserialport/LICENSE create mode 100755 libs/qextserialport/README create mode 100755 libs/qextserialport/doc/doc.pri create mode 100755 libs/qextserialport/doc/examples/enumerator.qdoc create mode 100755 libs/qextserialport/doc/examples/images/uartassistant.png create mode 100755 libs/qextserialport/doc/examples/qespta.qdoc create mode 100755 libs/qextserialport/doc/examples/uartassistant.qdoc create mode 100755 libs/qextserialport/doc/index.qdoc create mode 100755 libs/qextserialport/doc/qextserialport.qdocconf create mode 100755 libs/qextserialport/doc/readme.txt create mode 100755 libs/qextserialport/doc/style/style.css create mode 100755 libs/qextserialport/examples/enumerator/enumerator.pro create mode 100755 libs/qextserialport/examples/enumerator/main.cpp create mode 100755 libs/qextserialport/examples/event/PortListener.cpp create mode 100755 libs/qextserialport/examples/event/PortListener.h create mode 100755 libs/qextserialport/examples/event/event.pro create mode 100755 libs/qextserialport/examples/event/main.cpp create mode 100755 libs/qextserialport/examples/examples.pro create mode 100755 libs/qextserialport/examples/qespta/MainWindow.cpp create mode 100755 libs/qextserialport/examples/qespta/MainWindow.h create mode 100755 libs/qextserialport/examples/qespta/MessageWindow.cpp create mode 100755 libs/qextserialport/examples/qespta/MessageWindow.h create mode 100755 libs/qextserialport/examples/qespta/QespTest.cpp create mode 100755 libs/qextserialport/examples/qespta/QespTest.h create mode 100755 libs/qextserialport/examples/qespta/README create mode 100755 libs/qextserialport/examples/qespta/main.cpp create mode 100755 libs/qextserialport/examples/qespta/qespta.pro create mode 100755 libs/qextserialport/examples/uartassistant/dialog.cpp create mode 100755 libs/qextserialport/examples/uartassistant/dialog.h create mode 100755 libs/qextserialport/examples/uartassistant/dialog.ui create mode 100755 libs/qextserialport/examples/uartassistant/hled.cpp create mode 100755 libs/qextserialport/examples/uartassistant/hled.h create mode 100755 libs/qextserialport/examples/uartassistant/main.cpp create mode 100755 libs/qextserialport/examples/uartassistant/uartassistant.pro create mode 100755 libs/qextserialport/extserialport.prf.in create mode 100755 libs/qextserialport/qextserialport.pro create mode 100755 libs/qextserialport/src/qextserialenumerator.cpp create mode 100755 libs/qextserialport/src/qextserialenumerator.h create mode 100755 libs/qextserialport/src/qextserialenumerator_linux.cpp create mode 100755 libs/qextserialport/src/qextserialenumerator_osx.cpp create mode 100755 libs/qextserialport/src/qextserialenumerator_p.h create mode 100755 libs/qextserialport/src/qextserialenumerator_unix.cpp create mode 100755 libs/qextserialport/src/qextserialenumerator_win.cpp create mode 100755 libs/qextserialport/src/qextserialport.cpp create mode 100755 libs/qextserialport/src/qextserialport.h create mode 100755 libs/qextserialport/src/qextserialport.pri create mode 100755 libs/qextserialport/src/qextserialport_global.h create mode 100755 libs/qextserialport/src/qextserialport_p.h create mode 100755 libs/qextserialport/src/qextserialport_unix.cpp create mode 100755 libs/qextserialport/src/qextserialport_win.cpp diff --git a/libs/qextserialport/.gitignore b/libs/qextserialport/.gitignore new file mode 100644 index 000000000..e83cf5f9a --- /dev/null +++ b/libs/qextserialport/.gitignore @@ -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.* diff --git a/libs/qextserialport/ChangeLog b/libs/qextserialport/ChangeLog new file mode 100755 index 000000000..a632293d6 --- /dev/null +++ b/libs/qextserialport/ChangeLog @@ -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 : + + 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) : + (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) : + + 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. diff --git a/libs/qextserialport/LICENSE b/libs/qextserialport/LICENSE new file mode 100755 index 000000000..a8056fc1b --- /dev/null +++ b/libs/qextserialport/LICENSE @@ -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. diff --git a/libs/qextserialport/README b/libs/qextserialport/README new file mode 100755 index 000000000..3a9603e62 --- /dev/null +++ b/libs/qextserialport/README @@ -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) + diff --git a/libs/qextserialport/doc/doc.pri b/libs/qextserialport/doc/doc.pri new file mode 100755 index 000000000..5d1babb23 --- /dev/null +++ b/libs/qextserialport/doc/doc.pri @@ -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" + diff --git a/libs/qextserialport/doc/examples/enumerator.qdoc b/libs/qextserialport/doc/examples/enumerator.qdoc new file mode 100755 index 000000000..eab0ff8fc --- /dev/null +++ b/libs/qextserialport/doc/examples/enumerator.qdoc @@ -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 +*/ + diff --git a/libs/qextserialport/doc/examples/images/uartassistant.png b/libs/qextserialport/doc/examples/images/uartassistant.png new file mode 100755 index 0000000000000000000000000000000000000000..1b500b867596e1d4cc306ecc26d34b48727d559c GIT binary patch literal 20753 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 tU(Xj@R-a^U~~ literal 0 HcmV?d00001 diff --git a/libs/qextserialport/doc/examples/qespta.qdoc b/libs/qextserialport/doc/examples/qespta.qdoc new file mode 100755 index 000000000..035ab294d --- /dev/null +++ b/libs/qextserialport/doc/examples/qespta.qdoc @@ -0,0 +1,7 @@ +/*! + \example examples/qespta + \title qespta Demo + + The example demonstrates how to use QextSerialPort. +*/ + diff --git a/libs/qextserialport/doc/examples/uartassistant.qdoc b/libs/qextserialport/doc/examples/uartassistant.qdoc new file mode 100755 index 000000000..7ad6b8efa --- /dev/null +++ b/libs/qextserialport/doc/examples/uartassistant.qdoc @@ -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 +*/ + diff --git a/libs/qextserialport/doc/index.qdoc b/libs/qextserialport/doc/index.qdoc new file mode 100755 index 000000000..9c95f4c82 --- /dev/null +++ b/libs/qextserialport/doc/index.qdoc @@ -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 +*/ diff --git a/libs/qextserialport/doc/qextserialport.qdocconf b/libs/qextserialport/doc/qextserialport.qdocconf new file mode 100755 index 000000000..5e7abfd98 --- /dev/null +++ b/libs/qextserialport/doc/qextserialport.qdocconf @@ -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 = " \n" +HTML.endheader = "\n" + +HTML.postheader = "\n" \ + "\n" \ + "
" \ + "Home ·" \ + " All Classes ·" \ + "
" + +HTML.footer = "


\n" \ + "\n" \ + "\n" \ + "\n" \ + "\n" \ + "
Copyright © 2000-2012QextSerialPort Project
QextSerialPort Manual
" diff --git a/libs/qextserialport/doc/readme.txt b/libs/qextserialport/doc/readme.txt new file mode 100755 index 000000000..e97b883e6 --- /dev/null +++ b/libs/qextserialport/doc/readme.txt @@ -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... + diff --git a/libs/qextserialport/doc/style/style.css b/libs/qextserialport/doc/style/style.css new file mode 100755 index 000000000..0a5959f9e --- /dev/null +++ b/libs/qextserialport/doc/style/style.css @@ -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; +} diff --git a/libs/qextserialport/examples/enumerator/enumerator.pro b/libs/qextserialport/examples/enumerator/enumerator.pro new file mode 100755 index 000000000..96557d0d1 --- /dev/null +++ b/libs/qextserialport/examples/enumerator/enumerator.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +DEPENDPATH += . +CONFIG += console +include(../../src/qextserialport.pri) +SOURCES += main.cpp + diff --git a/libs/qextserialport/examples/enumerator/main.cpp b/libs/qextserialport/examples/enumerator/main.cpp new file mode 100755 index 000000000..e0a6e8cf9 --- /dev/null +++ b/libs/qextserialport/examples/enumerator/main.cpp @@ -0,0 +1,31 @@ +/** + * @file main.cpp + * @brief Main file. + * @author Micha? Policht + */ +//! [0] +#include "qextserialenumerator.h" +//! [0] +#include +#include +int main() +{ + //! [1] + QList 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; +} + diff --git a/libs/qextserialport/examples/event/PortListener.cpp b/libs/qextserialport/examples/event/PortListener.cpp new file mode 100755 index 000000000..51df8f1fc --- /dev/null +++ b/libs/qextserialport/examples/event/PortListener.cpp @@ -0,0 +1,43 @@ + +#include "PortListener.h" +#include + +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"; +} diff --git a/libs/qextserialport/examples/event/PortListener.h b/libs/qextserialport/examples/event/PortListener.h new file mode 100755 index 000000000..c7d06f5da --- /dev/null +++ b/libs/qextserialport/examples/event/PortListener.h @@ -0,0 +1,26 @@ + + + +#ifndef PORTLISTENER_H_ +#define PORTLISTENER_H_ + +#include +#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_*/ diff --git a/libs/qextserialport/examples/event/event.pro b/libs/qextserialport/examples/event/event.pro new file mode 100755 index 000000000..f8e1b6f26 --- /dev/null +++ b/libs/qextserialport/examples/event/event.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +DEPENDPATH += . +CONFIG += console +include(../../src/qextserialport.pri) + +SOURCES += main.cpp PortListener.cpp +HEADERS += PortListener.h diff --git a/libs/qextserialport/examples/event/main.cpp b/libs/qextserialport/examples/event/main.cpp new file mode 100755 index 000000000..dd92d23fb --- /dev/null +++ b/libs/qextserialport/examples/event/main.cpp @@ -0,0 +1,19 @@ +/** + * @file main.cpp + * @brief Main file. + * @author Michal Policht + */ + +#include +#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(); +} diff --git a/libs/qextserialport/examples/examples.pro b/libs/qextserialport/examples/examples.pro new file mode 100755 index 000000000..c7faf782e --- /dev/null +++ b/libs/qextserialport/examples/examples.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = qespta enumerator \ + uartassistant +win32:SUBDIRS += event + diff --git a/libs/qextserialport/examples/qespta/MainWindow.cpp b/libs/qextserialport/examples/qespta/MainWindow.cpp new file mode 100755 index 000000000..fa3dc7ec2 --- /dev/null +++ b/libs/qextserialport/examples/qespta/MainWindow.cpp @@ -0,0 +1,61 @@ +/** + * @file MainWindow.cpp + * @brief MainWindow Implementation. + * @see MainWindow.h + * @author Micha? Policht + */ + + +#include +#include +#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("""
" + "author: Michal Policht
" + "xpolik@users.sourceforge.net")); +} + +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); +} + diff --git a/libs/qextserialport/examples/qespta/MainWindow.h b/libs/qextserialport/examples/qespta/MainWindow.h new file mode 100755 index 000000000..91cffd4f0 --- /dev/null +++ b/libs/qextserialport/examples/qespta/MainWindow.h @@ -0,0 +1,38 @@ +/** + * @file MainWindow.h + * @brief Application's Main Window. + * @see MainWindow + * @author Micha? Policht + */ + +#ifndef MAINWINDOW_H_ +#define MAINWINDOW_H_ + +#include + +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_*/ + diff --git a/libs/qextserialport/examples/qespta/MessageWindow.cpp b/libs/qextserialport/examples/qespta/MessageWindow.cpp new file mode 100755 index 000000000..732c206b6 --- /dev/null +++ b/libs/qextserialport/examples/qespta/MessageWindow.cpp @@ -0,0 +1,102 @@ +/** + * @file MessageWindow.cpp + * @brief MessageWindow Implementation. + * @see MessageWindow.h + * @author Micha? Policht + */ + +#include +#include "MessageWindow.h" +#include +#include +#include + +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(event->type()) == MessageWindow::MessageEventType) + msgTextEdit.append(dynamic_cast(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("")); + qmsg.append(QLatin1String("")); + 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("")); + qmsg.append(QLatin1String("")); + 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(MessageWindow::MessageEventType)) +{ + this->msg = msg; +} diff --git a/libs/qextserialport/examples/qespta/MessageWindow.h b/libs/qextserialport/examples/qespta/MessageWindow.h new file mode 100755 index 000000000..183382be9 --- /dev/null +++ b/libs/qextserialport/examples/qespta/MessageWindow.h @@ -0,0 +1,84 @@ +/** + * @file MessageWindow.h + * @brief Message Window. + * @see MessageWindow + * @author Micha? Policht + */ + +#ifndef MESSAGEWINDOW_H_ +#define MESSAGEWINDOW_H_ + +#include +#include +#include + +/** + * 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_*/ diff --git a/libs/qextserialport/examples/qespta/QespTest.cpp b/libs/qextserialport/examples/qespta/QespTest.cpp new file mode 100755 index 000000000..66a0a8c62 --- /dev/null +++ b/libs/qextserialport/examples/qespta/QespTest.cpp @@ -0,0 +1,128 @@ +/* QespTest.cpp +**************************************/ +#include "QespTest.h" +#include "qextserialport.h" +#include +#include +#include +#include +#include + + +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()); +} + diff --git a/libs/qextserialport/examples/qespta/QespTest.h b/libs/qextserialport/examples/qespta/QespTest.h new file mode 100755 index 000000000..b26cfafd4 --- /dev/null +++ b/libs/qextserialport/examples/qespta/QespTest.h @@ -0,0 +1,36 @@ +/* qesptest.h +**************************************/ +#ifndef _QESPTEST_H_ +#define _QESPTEST_H_ + +#include + +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 diff --git a/libs/qextserialport/examples/qespta/README b/libs/qextserialport/examples/qespta/README new file mode 100755 index 000000000..edc23a3d4 --- /dev/null +++ b/libs/qextserialport/examples/qespta/README @@ -0,0 +1,4 @@ +This is simple application using QextSerialPort library. + +Port settings are in QespTest constructor (QespTest.cpp) + diff --git a/libs/qextserialport/examples/qespta/main.cpp b/libs/qextserialport/examples/qespta/main.cpp new file mode 100755 index 000000000..f232861a6 --- /dev/null +++ b/libs/qextserialport/examples/qespta/main.cpp @@ -0,0 +1,30 @@ +/** + * @file main.cpp + * @brief Main file. + * @author Micha? Policht + */ + +#include +#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(); +} + + diff --git a/libs/qextserialport/examples/qespta/qespta.pro b/libs/qextserialport/examples/qespta/qespta.pro new file mode 100755 index 000000000..bf271c45a --- /dev/null +++ b/libs/qextserialport/examples/qespta/qespta.pro @@ -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) diff --git a/libs/qextserialport/examples/uartassistant/dialog.cpp b/libs/qextserialport/examples/uartassistant/dialog.cpp new file mode 100755 index 000000000..6175ab31f --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/dialog.cpp @@ -0,0 +1,179 @@ +#include "qextserialport.h" +#include "qextserialenumerator.h" +#include "dialog.h" +#include "ui_dialog.h" +#include + +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] diff --git a/libs/qextserialport/examples/uartassistant/dialog.h b/libs/qextserialport/examples/uartassistant/dialog.h new file mode 100755 index 000000000..7e479787c --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/dialog.h @@ -0,0 +1,45 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include + +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 diff --git a/libs/qextserialport/examples/uartassistant/dialog.ui b/libs/qextserialport/examples/uartassistant/dialog.ui new file mode 100755 index 000000000..8f7e6535e --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/dialog.ui @@ -0,0 +1,191 @@ + + + Dialog + + + + 0 + 0 + 604 + 485 + + + + Dialog + + + + + + + + 800 + + + + + + + + + + + + + + + + Port: + + + + + + + + + + BaudRate: + + + + + + + + + + DataBits: + + + + + + + + + + Parity: + + + + + + + + + + StopBits: + + + + + + + + + + QueryMode: + + + + + + + + + + Timeout: + + + + + + + ms + + + -1 + + + 10000 + + + 10 + + + 10 + + + + + + + + + + + + 0 + 0 + + + + + 20 + 20 + + + + + 25 + 25 + + + + + + + + Open/Close + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Send + + + + + + + + + + + HLed + QWidget +
hled.h
+ 1 +
+
+ + +
diff --git a/libs/qextserialport/examples/uartassistant/hled.cpp b/libs/qextserialport/examples/uartassistant/hled.cpp new file mode 100755 index 000000000..6255e48ff --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/hled.cpp @@ -0,0 +1,133 @@ +#include +#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; +} + diff --git a/libs/qextserialport/examples/uartassistant/hled.h b/libs/qextserialport/examples/uartassistant/hled.h new file mode 100755 index 000000000..54225d60d --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/hled.h @@ -0,0 +1,34 @@ +#ifndef HLED_H +#define HLED_H + +#include + +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 diff --git a/libs/qextserialport/examples/uartassistant/main.cpp b/libs/qextserialport/examples/uartassistant/main.cpp new file mode 100755 index 000000000..7cace73cb --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/main.cpp @@ -0,0 +1,11 @@ +#include +#include "dialog.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Dialog w; + w.show(); + + return a.exec(); +} diff --git a/libs/qextserialport/examples/uartassistant/uartassistant.pro b/libs/qextserialport/examples/uartassistant/uartassistant.pro new file mode 100755 index 000000000..5e73141a8 --- /dev/null +++ b/libs/qextserialport/examples/uartassistant/uartassistant.pro @@ -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 diff --git a/libs/qextserialport/extserialport.prf.in b/libs/qextserialport/extserialport.prf.in new file mode 100755 index 000000000..aa6056bf7 --- /dev/null +++ b/libs/qextserialport/extserialport.prf.in @@ -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 diff --git a/libs/qextserialport/qextserialport.pro b/libs/qextserialport/qextserialport.pro new file mode 100755 index 000000000..e1e8a43ad --- /dev/null +++ b/libs/qextserialport/qextserialport.pro @@ -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 diff --git a/libs/qextserialport/src/qextserialenumerator.cpp b/libs/qextserialport/src/qextserialenumerator.cpp new file mode 100755 index 000000000..ec1491a74 --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator.cpp @@ -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 +#include +#include + +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 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"); +} + +/*! + Destructs the QextSerialEnumerator object. +*/ +QextSerialEnumerator::~QextSerialEnumerator() +{ + delete d_ptr; +} + +/*! + Get list of ports. + + return list of ports currently available in the system. +*/ +QList 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" diff --git a/libs/qextserialport/src/qextserialenumerator.h b/libs/qextserialport/src/qextserialenumerator.h new file mode 100755 index 000000000..99f515d58 --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator.h @@ -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 +#include +#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 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_*/ diff --git a/libs/qextserialport/src/qextserialenumerator_linux.cpp b/libs/qextserialport/src/qextserialenumerator_linux.cpp new file mode 100755 index 000000000..a57dfe639 --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator_linux.cpp @@ -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 +#include +#include + +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 QextSerialEnumeratorPrivate::getPorts_sys() +{ + QList 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 diff --git a/libs/qextserialport/src/qextserialenumerator_osx.cpp b/libs/qextserialport/src/qextserialenumerator_osx.cpp new file mode 100755 index 000000000..2dd03570c --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator_osx.cpp @@ -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 +#include +#include +#include + +void QextSerialEnumeratorPrivate::platformSpecificInit() +{ +} + +void QextSerialEnumeratorPrivate::platformSpecificDestruct() +{ + IONotificationPortDestroy(notificationPortRef); +} + +// static +QList QextSerialEnumeratorPrivate::getPorts_sys() +{ + QList 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 &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; +} + diff --git a/libs/qextserialport/src/qextserialenumerator_p.h b/libs/qextserialport/src/qextserialenumerator_p.h new file mode 100755 index 000000000..7bfebad5f --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator_p.h @@ -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 +#endif /*Q_OS_WIN*/ + +#ifdef Q_OS_MAC +# include +#endif /*Q_OS_MAC*/ + +#if defined(Q_OS_LINUX) && !defined(QESP_NO_UDEV) +# include +extern "C" { +# include +} +#endif + +class QextSerialRegistrationWidget; +class QextSerialEnumeratorPrivate +{ + Q_DECLARE_PUBLIC(QextSerialEnumerator) +public: + QextSerialEnumeratorPrivate(QextSerialEnumerator *enumrator); + ~QextSerialEnumeratorPrivate(); + void platformSpecificInit(); + void platformSpecificDestruct(); + + static QList 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 &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_ diff --git a/libs/qextserialport/src/qextserialenumerator_unix.cpp b/libs/qextserialport/src/qextserialenumerator_unix.cpp new file mode 100755 index 000000000..80a4ad426 --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator_unix.cpp @@ -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 + +void QextSerialEnumeratorPrivate::platformSpecificInit() +{ +} + +void QextSerialEnumeratorPrivate::platformSpecificDestruct() +{ +} + +QList QextSerialEnumeratorPrivate::getPorts_sys() +{ + QList 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; +} diff --git a/libs/qextserialport/src/qextserialenumerator_win.cpp b/libs/qextserialport/src/qextserialenumerator_win.cpp new file mode 100755 index 000000000..30b656c4f --- /dev/null +++ b/libs/qextserialport/src/qextserialenumerator_win.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include "qextserialport.h" + +#ifdef QT_GUI_LIB +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#include +class QextSerialRegistrationWidget : public QWidget +#else +#include +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); +#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 *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() QextSerialEnumeratorPrivate::getPorts_sys() +{ + QList ports; + const int count = sizeof(deviceClassGuids)/sizeof(deviceClassGuids[0]); + for (int i=0; iwinId(), &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; ideviceDiscovered(info); + else if (wParam == DBT_DEVICEREMOVECOMPLETE) + Q_EMIT q->deviceRemoved(info); + break; + } + } + SetupDiDestroyDeviceInfoList(devInfo); + } + return rv; +} diff --git a/libs/qextserialport/src/qextserialport.cpp b/libs/qextserialport/src/qextserialport.cpp new file mode 100755 index 000000000..119bef868 --- /dev/null +++ b/libs/qextserialport/src/qextserialport.cpp @@ -0,0 +1,1011 @@ +/**************************************************************************** +** 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 +#include +#include +#include + +/*! + \class PortSettings + + \brief The PortSettings class contain port settings + + Structure to contain port settings. + + \code + BaudRateType BaudRate; + DataBitsType DataBits; + ParityType Parity; + StopBitsType StopBits; + FlowType FlowControl; + long Timeout_Millisec; + \endcode +*/ + +QextSerialPortPrivate::QextSerialPortPrivate(QextSerialPort *q) + :lock(QReadWriteLock::Recursive), q_ptr(q) +{ + lastErr = E_NO_ERROR; + settings.BaudRate = BAUD9600; + settings.Parity = PAR_NONE; + settings.FlowControl = FLOW_OFF; + settings.DataBits = DATA_8; + settings.StopBits = STOP_1; + settings.Timeout_Millisec = 10; + settingsDirtyFlags = DFE_ALL; + + platformSpecificInit(); +} + +QextSerialPortPrivate::~QextSerialPortPrivate() +{ + platformSpecificDestruct(); +} + +void QextSerialPortPrivate::setBaudRate(BaudRateType baudRate, bool update) +{ + switch (baudRate) { +#ifdef Q_OS_WIN + //Windows Special + case BAUD14400: + case BAUD56000: + case BAUD128000: + case BAUD256000: + QESP_PORTABILITY_WARNING()<<"QextSerialPort Portability Warning: POSIX does not support baudRate:"<isOpen()) + updatePortSettings(); + break; +#if !(defined(Q_OS_WIN) || defined(Q_OS_MAC)) + default: + QESP_WARNING()<<"QextSerialPort does not support baudRate:"<isOpen()) + updatePortSettings(); +} + +void QextSerialPortPrivate::setDataBits(DataBitsType dataBits, bool update) +{ + switch(dataBits) { + + case DATA_5: + if (settings.StopBits == STOP_2) { + QESP_WARNING("QextSerialPort: 5 Data bits cannot be used with 2 stop bits."); + } + else { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + break; + + case DATA_6: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 6 Data bits cannot be used with 1.5 stop bits."); + } + else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + break; + + case DATA_7: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 7 Data bits cannot be used with 1.5 stop bits."); + } + else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + break; + + case DATA_8: +#ifdef Q_OS_WIN + if (settings.StopBits == STOP_1_5) { + QESP_WARNING("QextSerialPort: 8 Data bits cannot be used with 1.5 stop bits."); + } + else +#endif + { + settings.DataBits = dataBits; + settingsDirtyFlags |= DFE_DataBits; + } + break; + default: + QESP_WARNING()<<"QextSerialPort does not support Data bits:"<isOpen()) + updatePortSettings(); +} + +void QextSerialPortPrivate::setStopBits(StopBitsType stopBits, bool update) +{ + switch (stopBits) { + + /*one stop bit*/ + case STOP_1: + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + break; + +#ifdef Q_OS_WIN + /*1.5 stop bits*/ + case STOP_1_5: + QESP_PORTABILITY_WARNING("QextSerialPort Portability Warning: 1.5 stop bit operation is not supported by POSIX."); + if (settings.DataBits != DATA_5) { + QESP_WARNING("QextSerialPort: 1.5 stop bits can only be used with 5 data bits"); + } + else { + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + } + break; +#endif + + /*two stop bits*/ + case STOP_2: + if (settings.DataBits == DATA_5) { + QESP_WARNING("QextSerialPort: 2 stop bits cannot be used with 5 data bits"); + } + else { + settings.StopBits = stopBits; + settingsDirtyFlags |= DFE_StopBits; + } + break; + default: + QESP_WARNING()<<"QextSerialPort does not support stop bits: "<isOpen()) + updatePortSettings(); +} + +void QextSerialPortPrivate::setFlowControl(FlowType flow, bool update) +{ + settings.FlowControl = flow; + settingsDirtyFlags |= DFE_Flow; + if (update && q_func()->isOpen()) + updatePortSettings(); +} + +void QextSerialPortPrivate::setTimeout(long millisec, bool update) +{ + settings.Timeout_Millisec = millisec; + settingsDirtyFlags |= DFE_TimeOut; + if (update && q_func()->isOpen()) + updatePortSettings(); +} + +void QextSerialPortPrivate::setPortSettings(const PortSettings &settings, bool update) +{ + setBaudRate(settings.BaudRate, false); + setDataBits(settings.DataBits, false); + setStopBits(settings.StopBits, false); + setParity(settings.Parity, false); + setFlowControl(settings.FlowControl, false); + setTimeout(settings.Timeout_Millisec, false); + settingsDirtyFlags = DFE_ALL; + if (update && q_func()->isOpen()) + updatePortSettings(); +} + + +void QextSerialPortPrivate::_q_canRead() +{ + qint64 maxSize = bytesAvailable_sys(); + if (maxSize > 0) { + char *writePtr = readBuffer.reserve(size_t(maxSize)); + qint64 bytesRead = readData_sys(writePtr, maxSize); + if (bytesRead < maxSize) + readBuffer.chop(maxSize - bytesRead); + Q_Q(QextSerialPort); + Q_EMIT q->readyRead(); + } +} + +/*! \class QextSerialPort + + \brief The QextSerialPort class encapsulates a serial port on both POSIX and Windows systems. + + \section1 Usage + QextSerialPort offers both a polling and event driven API. Event driven + is typically easier to use, since you never have to worry about checking + for new data. + + \bold Example + \code + QextSerialPort *port = new QextSerialPort("COM1"); + connect(port, SIGNAL(readyRead()), myClass, SLOT(onDataAvailable())); + port->open(); + + void MyClass::onDataAvailable() + { + QByteArray data = port->readAll(); + processNewData(usbdata); + } + \endcode + + \section1 Compatibility + The user will be notified of errors and possible portability conflicts at run-time + by default. + + For example, if a application has used BAUD1800, when it is runing under unix, you + will get following message. + + \code + QextSerialPort Portability Warning: Windows does not support baudRate:1800 + \endcode + + This behavior can be turned off by defining macro QESP_NO_WARN (to turn off all warnings) + or QESP_NO_PORTABILITY_WARN (to turn off portability warnings) in the project. + + + \bold Author: Stefan Sander, Michal Policht, Brandon Fosdick, Liam Staskawicz, Debao Zhang +*/ + +/*! + \enum QextSerialPort::QueryMode + + This enum type specifies query mode used in a serial port: + + \value Polling + asynchronously read and write + \value EventDriven + synchronously read and write +*/ + +/*! + \fn void QextSerialPort::dsrChanged(bool status) + This signal is emitted whenever dsr line has changed its state. You may + use this signal to check if device is connected. + + \a status true when DSR signal is on, false otherwise. + */ + + +/*! + \fn QueryMode QextSerialPort::queryMode() const + Get query mode. + */ + +/*! + Default constructor. Note that the name of the device used by a QextSerialPort is dependent on + your OS. Possible naming conventions and their associated OS are: + + \code + + OS Constant Used By Naming Convention + ------------- ------------- ------------------------ + Q_OS_WIN Windows COM1, COM2 + Q_OS_IRIX SGI/IRIX /dev/ttyf1, /dev/ttyf2 + Q_OS_HPUX HP-UX /dev/tty1p0, /dev/tty2p0 + Q_OS_SOLARIS SunOS/Slaris /dev/ttya, /dev/ttyb + Q_OS_OSF Digital UNIX /dev/tty01, /dev/tty02 + Q_OS_FREEBSD FreeBSD /dev/ttyd0, /dev/ttyd1 + Q_OS_OPENBSD OpenBSD /dev/tty00, /dev/tty01 + Q_OS_LINUX Linux /dev/ttyS0, /dev/ttyS1 + /dev/ttyS0, /dev/ttyS1 + \endcode + + This constructor assigns the device name to the name of the first port on the specified system. + See the other constructors if you need to open a different port. Default \a mode is EventDriven. + As a subclass of QObject, \a parent can be specified. +*/ + +QextSerialPort::QextSerialPort(QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ +#ifdef Q_OS_WIN + setPortName(QLatin1String("COM1")); + +#elif defined(Q_OS_IRIX) + setPortName(QLatin1String("/dev/ttyf1")); + +#elif defined(Q_OS_HPUX) + setPortName(QLatin1String("/dev/tty1p0")); + +#elif defined(Q_OS_SOLARIS) + setPortName(QLatin1String("/dev/ttya")); + +#elif defined(Q_OS_OSF) //formally DIGITAL UNIX + setPortName(QLatin1String("/dev/tty01")); + +#elif defined(Q_OS_FREEBSD) + setPortName(QLatin1String("/dev/ttyd1")); + +#elif defined(Q_OS_OPENBSD) + setPortName(QLatin1String("/dev/tty00")); + +#else + setPortName(QLatin1String("/dev/ttyS0")); +#endif + setQueryMode(mode); +} + +/*! + Constructs a serial port attached to the port specified by name. + \a name is the name of the device, which is windowsystem-specific, + e.g."COM1" or "/dev/ttyS0". \a mode +*/ +QextSerialPort::QextSerialPort(const QString &name, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + setQueryMode(mode); + setPortName(name); +} + +/*! + Constructs a port with default name and specified \a settings. +*/ +QextSerialPort::QextSerialPort(const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + Q_D(QextSerialPort); + setQueryMode(mode); + d->setPortSettings(settings); +} + +/*! + Constructs a port with specified \a name , \a mode and \a settings. +*/ +QextSerialPort::QextSerialPort(const QString &name, const PortSettings &settings, QextSerialPort::QueryMode mode, QObject *parent) + : QIODevice(parent), d_ptr(new QextSerialPortPrivate(this)) +{ + Q_D(QextSerialPort); + setPortName(name); + setQueryMode(mode); + d->setPortSettings(settings); +} + +/*! + Opens a serial port and sets its OpenMode to \a mode. + Note that this function does not specify which device to open. + Returns true if successful; otherwise returns false.This function has no effect + if the port associated with the class is already open. The port is also + configured to the current settings, as stored in the settings structure. +*/ +bool QextSerialPort::open(OpenMode mode) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (mode != QIODevice::NotOpen && !isOpen()) + d->open_sys(mode); + + return isOpen(); +} + + +/*! \reimp + Closes a serial port. This function has no effect if the serial port associated with the class + is not currently open. +*/ +void QextSerialPort::close() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (isOpen()) { + // Be a good QIODevice and call QIODevice::close() before really close() + // so the aboutToClose() signal is emitted at the proper time + QIODevice::close(); // mark ourselves as closed + d->close_sys(); + d->readBuffer.clear(); + } +} + +/*! + Flushes all pending I/O to the serial port. This function has no effect if the serial port + associated with the class is not currently open. +*/ +void QextSerialPort::flush() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (isOpen()) + d->flush_sys(); +} + +/*! \reimp + Returns the number of bytes waiting in the port's receive queue. This function will return 0 if + the port is not currently open, or -1 on error. +*/ +qint64 QextSerialPort::bytesAvailable() const +{ + QWriteLocker locker(&d_func()->lock); + if (isOpen()) { + qint64 bytes = d_func()->bytesAvailable_sys(); + if (bytes != -1) { + return bytes + d_func()->readBuffer.size() + + QIODevice::bytesAvailable(); + } else { + return -1; + } + } + return 0; +} + +/*! \reimp + +*/ +bool QextSerialPort::canReadLine() const +{ + QReadLocker locker(&d_func()->lock); + return QIODevice::canReadLine() || d_func()->readBuffer.canReadLine(); +} + +/*! + * Set desired serial communication handling style. You may choose from polling + * or event driven approach. This function does nothing when port is open; to + * apply changes port must be reopened. + * + * In event driven approach read() and write() functions are acting + * asynchronously. They return immediately and the operation is performed in + * the background, so they doesn't freeze the calling thread. + * To determine when operation is finished, QextSerialPort runs separate thread + * and monitors serial port events. Whenever the event occurs, adequate signal + * is emitted. + * + * When polling is set, read() and write() are acting synchronously. Signals are + * not working in this mode and some functions may not be available. The advantage + * of polling is that it generates less overhead due to lack of signals emissions + * and it doesn't start separate thread to monitor events. + * + * Generally event driven approach is more capable and friendly, although some + * applications may need as low overhead as possible and then polling comes. + * + * \a mode query mode. + */ +void QextSerialPort::setQueryMode(QueryMode mode) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (mode != d->queryMode) { + d->queryMode = mode; + } +} + +/*! + Sets the \a name of the device associated with the object, e.g. "COM1", or "/dev/ttyS0". +*/ +void QextSerialPort::setPortName(const QString &name) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + d->port = name; +} + +/*! + Returns the name set by setPortName(). +*/ +QString QextSerialPort::portName() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->port; +} + +QextSerialPort::QueryMode QextSerialPort::queryMode() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->queryMode; +} + +/*! + Reads all available data from the device, and returns it as a QByteArray. + This function has no way of reporting errors; returning an empty QByteArray() + can mean either that no data was currently available for reading, or that an error occurred. +*/ +QByteArray QextSerialPort::readAll() +{ + int avail = this->bytesAvailable(); + return (avail > 0) ? this->read(avail) : QByteArray(); +} + +/*! + Returns the baud rate of the serial port. For a list of possible return values see + the definition of the enum BaudRateType. +*/ +BaudRateType QextSerialPort::baudRate() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.BaudRate; +} + +/*! + Returns the number of data bits used by the port. For a list of possible values returned by + this function, see the definition of the enum DataBitsType. +*/ +DataBitsType QextSerialPort::dataBits() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.DataBits; +} + +/*! + Returns the type of parity used by the port. For a list of possible values returned by + this function, see the definition of the enum ParityType. +*/ +ParityType QextSerialPort::parity() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.Parity; +} + +/*! + Returns the number of stop bits used by the port. For a list of possible return values, see + the definition of the enum StopBitsType. +*/ +StopBitsType QextSerialPort::stopBits() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.StopBits; +} + +/*! + Returns the type of flow control used by the port. For a list of possible values returned + by this function, see the definition of the enum FlowType. +*/ +FlowType QextSerialPort::flowControl() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->settings.FlowControl; +} + +/*! + \reimp + Returns true if device is sequential, otherwise returns false. Serial port is sequential device + so this function always returns true. Check QIODevice::isSequential() documentation for more + information. +*/ +bool QextSerialPort::isSequential() const +{ + return true; +} + +/*! + Return the error number, or 0 if no error occurred. +*/ +ulong QextSerialPort::lastError() const +{ + QReadLocker locker(&d_func()->lock); + return d_func()->lastErr; +} + +/*! + Returns the line status as stored by the port function. This function will retrieve the states + of the following lines: DCD, CTS, DSR, and RI. On POSIX systems, the following additional lines + can be monitored: DTR, RTS, Secondary TXD, and Secondary RXD. The value returned is an unsigned + long with specific bits indicating which lines are high. The following constants should be used + to examine the states of individual lines: + + \code + Mask Line + ------ ---- + LS_CTS CTS + LS_DSR DSR + LS_DCD DCD + LS_RI RI + LS_RTS RTS (POSIX only) + LS_DTR DTR (POSIX only) + LS_ST Secondary TXD (POSIX only) + LS_SR Secondary RXD (POSIX only) + \endcode + + This function will return 0 if the port associated with the class is not currently open. +*/ +unsigned long QextSerialPort::lineStatus() +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (isOpen()) + return d->lineStatus_sys(); + return 0; +} + +/*! + Returns a human-readable description of the last device error that occurred. +*/ +QString QextSerialPort::errorString() +{ + Q_D(QextSerialPort); + QReadLocker locker(&d->lock); + switch(d->lastErr) { + case E_NO_ERROR: + return tr("No Error has occurred"); + case E_INVALID_FD: + return tr("Invalid file descriptor (port was not opened correctly)"); + case E_NO_MEMORY: + return tr("Unable to allocate memory tables (POSIX)"); + case E_CAUGHT_NON_BLOCKED_SIGNAL: + return tr("Caught a non-blocked signal (POSIX)"); + case E_PORT_TIMEOUT: + return tr("Operation timed out (POSIX)"); + case E_INVALID_DEVICE: + return tr("The file opened by the port is not a valid device"); + case E_BREAK_CONDITION: + return tr("The port detected a break condition"); + case E_FRAMING_ERROR: + return tr("The port detected a framing error (usually caused by incorrect baud rate settings)"); + case E_IO_ERROR: + return tr("There was an I/O error while communicating with the port"); + case E_BUFFER_OVERRUN: + return tr("Character buffer overrun"); + case E_RECEIVE_OVERFLOW: + return tr("Receive buffer overflow"); + case E_RECEIVE_PARITY_ERROR: + return tr("The port detected a parity error in the received data"); + case E_TRANSMIT_OVERFLOW: + return tr("Transmit buffer overflow"); + case E_READ_FAILED: + return tr("General read operation failure"); + case E_WRITE_FAILED: + return tr("General write operation failure"); + case E_FILE_NOT_FOUND: + return tr("The %1 file doesn't exists").arg(this->portName()); + case E_PERMISSION_DENIED: + return tr("Permission denied"); + case E_AGAIN: + return tr("Device is already locked"); + default: + return tr("Unknown error: %1").arg(d->lastErr); + } +} + +/*! + Destructs the QextSerialPort object. +*/ +QextSerialPort::~QextSerialPort() +{ + if (isOpen()) { + close(); + } + delete d_ptr; +} + +/*! + Sets the flow control used by the port to \a flow. Possible values of flow are: + \code + FLOW_OFF No flow control + FLOW_HARDWARE Hardware (RTS/CTS) flow control + FLOW_XONXOFF Software (XON/XOFF) flow control + \endcode +*/ +void QextSerialPort::setFlowControl(FlowType flow) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.FlowControl != flow) + d->setFlowControl(flow, true); +} + +/*! + Sets the parity associated with the serial port to \a parity. The possible values of parity are: + \code + PAR_SPACE Space Parity + PAR_MARK Mark Parity + PAR_NONE No Parity + PAR_EVEN Even Parity + PAR_ODD Odd Parity + \endcode +*/ +void QextSerialPort::setParity(ParityType parity) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.Parity != parity) + d->setParity(parity, true); +} + +/*! + Sets the number of data bits used by the serial port to \a dataBits. Possible values of dataBits are: + \code + DATA_5 5 data bits + DATA_6 6 data bits + DATA_7 7 data bits + DATA_8 8 data bits + \endcode + + \bold note: + This function is subject to the following restrictions: + \list + \o 5 data bits cannot be used with 2 stop bits. + \o 1.5 stop bits can only be used with 5 data bits. + \o 8 data bits cannot be used with space parity on POSIX systems. + \endlist + */ +void QextSerialPort::setDataBits(DataBitsType dataBits) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.DataBits != dataBits) + d->setDataBits(dataBits, true); +} + +/*! + Sets the number of stop bits used by the serial port to \a stopBits. Possible values of stopBits are: + \code + STOP_1 1 stop bit + STOP_1_5 1.5 stop bits + STOP_2 2 stop bits + \endcode + + \bold note: + This function is subject to the following restrictions: + \list + \o 2 stop bits cannot be used with 5 data bits. + \o 1.5 stop bits cannot be used with 6 or more data bits. + \o POSIX does not support 1.5 stop bits. + \endlist +*/ +void QextSerialPort::setStopBits(StopBitsType stopBits) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.StopBits != stopBits) + d->setStopBits(stopBits, true); +} + +/*! + Sets the baud rate of the serial port to \a baudRate. Note that not all rates are applicable on + all platforms. The following table shows translations of the various baud rate + constants on Windows(including NT/2000) and POSIX platforms. Speeds marked with an * + are speeds that are usable on both Windows and POSIX. + \code + + RATE Windows Speed POSIX Speed + ----------- ------------- ----------- + BAUD50 X 50 + BAUD75 X 75 + *BAUD110 110 110 + BAUD134 X 134.5 + BAUD150 X 150 + BAUD200 X 200 + *BAUD300 300 300 + *BAUD600 600 600 + *BAUD1200 1200 1200 + BAUD1800 X 1800 + *BAUD2400 2400 2400 + *BAUD4800 4800 4800 + *BAUD9600 9600 9600 + BAUD14400 14400 X + *BAUD19200 19200 19200 + *BAUD38400 38400 38400 + BAUD56000 56000 X + *BAUD57600 57600 57600 + BAUD76800 X 76800 + *BAUD115200 115200 115200 + BAUD128000 128000 X + BAUD230400 X 230400 + BAUD256000 256000 X + BAUD460800 X 460800 + BAUD500000 X 500000 + BAUD576000 X 576000 + BAUD921600 X 921600 + BAUD1000000 X 1000000 + BAUD1152000 X 1152000 + BAUD1500000 X 1500000 + BAUD2000000 X 2000000 + BAUD2500000 X 2500000 + BAUD3000000 X 3000000 + BAUD3500000 X 3500000 + BAUD4000000 X 4000000 + \endcode +*/ + +void QextSerialPort::setBaudRate(BaudRateType baudRate) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.BaudRate != baudRate) + d->setBaudRate(baudRate, true); +} + +/*! + For Unix: + + Sets the read and write timeouts for the port to \a millisec milliseconds. + Note that this is a per-character timeout, i.e. the port will wait this long for each + individual character, not for the whole read operation. This timeout also applies to the + bytesWaiting() function. + + \bold note: + POSIX does not support millisecond-level control for I/O timeout values. Any + timeout set using this function will be set to the next lowest tenth of a second for + the purposes of detecting read or write timeouts. For example a timeout of 550 milliseconds + will be seen by the class as a timeout of 500 milliseconds for the purposes of reading and + writing the port. However millisecond-level control is allowed by the select() system call, + so for example a 550-millisecond timeout will be seen as 550 milliseconds on POSIX systems for + the purpose of detecting available bytes in the read buffer. + + For Windows: + + Sets the read and write timeouts for the port to \a millisec milliseconds. + Setting 0 indicates that timeouts are not used for read nor write operations; + however read() and write() functions will still block. Set -1 to provide + non-blocking behaviour (read() and write() will return immediately). + + \bold note: this function does nothing in event driven mode. +*/ +void QextSerialPort::setTimeout(long millisec) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (d->settings.Timeout_Millisec != millisec) + d->setTimeout(millisec, true); +} + +/*! + Sets DTR line to the requested state (\a set default to high). This function will have no effect if + the port associated with the class is not currently open. +*/ +void QextSerialPort::setDtr(bool set) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (isOpen()) + d->setDtr_sys(set); +} + +/*! + Sets RTS line to the requested state \a set (high by default). + This function will have no effect if + the port associated with the class is not currently open. +*/ +void QextSerialPort::setRts(bool set) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + if (isOpen()) + d->setRts_sys(set); +} + +/*! \reimp + Reads a block of data from the serial port. This function will read at most maxlen bytes from + the serial port and place them in the buffer pointed to by data. Return value is the number of + bytes actually read, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::readData(char *data, qint64 maxSize) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + qint64 bytesFromBuffer = 0; + if (!d->readBuffer.isEmpty()) { + bytesFromBuffer = d->readBuffer.read(data, maxSize); + if (bytesFromBuffer == maxSize) + return bytesFromBuffer; + } + qint64 bytesFromDevice = d->readData_sys(data+bytesFromBuffer, maxSize-bytesFromBuffer); + if (bytesFromDevice < 0) { + return -1; + } + return bytesFromBuffer + bytesFromDevice; +} + +/*! \reimp + Writes a block of data to the serial port. This function will write len bytes + from the buffer pointed to by data to the serial port. Return value is the number + of bytes actually written, or -1 on error. + + \warning before calling this function ensure that serial port associated with this class + is currently open (use isOpen() function to check if port is open). +*/ +qint64 QextSerialPort::writeData(const char *data, qint64 maxSize) +{ + Q_D(QextSerialPort); + QWriteLocker locker(&d->lock); + return d->writeData_sys(data, maxSize); +} + +#include "moc_qextserialport.cpp" diff --git a/libs/qextserialport/src/qextserialport.h b/libs/qextserialport/src/qextserialport.h new file mode 100755 index 000000000..5334e94b2 --- /dev/null +++ b/libs/qextserialport/src/qextserialport.h @@ -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 +#include "qextserialport_global.h" +#ifdef Q_OS_UNIX +#include +#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 diff --git a/libs/qextserialport/src/qextserialport.pri b/libs/qextserialport/src/qextserialport.pri new file mode 100755 index 000000000..461d56f64 --- /dev/null +++ b/libs/qextserialport/src/qextserialport.pri @@ -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__ diff --git a/libs/qextserialport/src/qextserialport_global.h b/libs/qextserialport/src/qextserialport_global.h new file mode 100755 index 000000000..824d45542 --- /dev/null +++ b/libs/qextserialport/src/qextserialport_global.h @@ -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 + +#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 + diff --git a/libs/qextserialport/src/qextserialport_p.h b/libs/qextserialport/src/qextserialport_p.h new file mode 100755 index 000000000..d278a17e9 --- /dev/null +++ b/libs/qextserialport/src/qextserialport_p.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 +#ifdef Q_OS_UNIX +# include +#elif (defined Q_OS_WIN) +# include +#endif +#include + +// 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(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(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 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_ diff --git a/libs/qextserialport/src/qextserialport_unix.cpp b/libs/qextserialport/src/qextserialport_unix.cpp new file mode 100755 index 000000000..4c02a206d --- /dev/null +++ b/libs/qextserialport/src/qextserialport_unix.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/libs/qextserialport/src/qextserialport_win.cpp b/libs/qextserialport/src/qextserialport_win.cpp new file mode 100755 index 000000000..4dfd97ac3 --- /dev/null +++ b/libs/qextserialport/src/qextserialport_win.cpp @@ -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 +#include +#include +#include +#include +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +# include +#else +# include +#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:"<("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:"<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 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; +} diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index c7057995c..0c0b7088e 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -194,6 +194,8 @@ ReleaseBuild { } } +include(libs/qextserialport/src/qextserialport.pri) + # # External library configuration # diff --git a/src/ui/px4_configuration/PX4Bootloader.cc b/src/ui/px4_configuration/PX4Bootloader.cc index 51c6d3310..556b57409 100644 --- a/src/ui/px4_configuration/PX4Bootloader.cc +++ b/src/ui/px4_configuration/PX4Bootloader.cc @@ -32,6 +32,8 @@ #include #include +#include "QGC.h" + static const quint32 crctab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, @@ -76,22 +78,24 @@ static quint32 crc32(const uint8_t *src, unsigned len, unsigned state) return state; } +#if 0 const struct PX4Bootloader::serialPortErrorString PX4Bootloader::_rgSerialPortErrors[14] = { - { QSerialPort::NoError, "No error occurred." }, - { QSerialPort::DeviceNotFoundError, "An error occurred while attempting to open a non-existing device." }, - { QSerialPort::PermissionError, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open." }, - { QSerialPort::OpenError, "An error occurred while attempting to open an already opened device in this object." }, - { QSerialPort::NotOpenError, "This error occurs when an operation is executed that can only be successfully performed if the device is open." }, - { QSerialPort::ParityError, "Parity error detected by the hardware while reading data." }, - { QSerialPort::FramingError, "Framing error detected by the hardware while reading data." }, - { QSerialPort::BreakConditionError, "Break condition detected by the hardware on the input line." }, - { QSerialPort::WriteError, "An I/O error occurred while writing the data." }, - { QSerialPort::ReadError, "An I/O error occurred while reading the data." }, - { QSerialPort::ResourceError, "An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system." }, - { QSerialPort::UnsupportedOperationError, "The requested device operation is not supported or prohibited by the running operating system." }, - { QSerialPort::TimeoutError, "A timeout error occurred." }, - { QSerialPort::UnknownError, "An unidentified error occurred." } + { QextSerialPort::NoError, "No error occurred." }, + { QextSerialPort::DeviceNotFoundError, "An error occurred while attempting to open a non-existing device." }, + { QextSerialPort::PermissionError, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open." }, + { QextSerialPort::OpenError, "An error occurred while attempting to open an already opened device in this object." }, + { QextSerialPort::NotOpenError, "This error occurs when an operation is executed that can only be successfully performed if the device is open." }, + { QextSerialPort::ParityError, "Parity error detected by the hardware while reading data." }, + { QextSerialPort::FramingError, "Framing error detected by the hardware while reading data." }, + { QextSerialPort::BreakConditionError, "Break condition detected by the hardware on the input line." }, + { QextSerialPort::WriteError, "An I/O error occurred while writing the data." }, + { QextSerialPort::ReadError, "An I/O error occurred while reading the data." }, + { QextSerialPort::ResourceError, "An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system." }, + { QextSerialPort::UnsupportedOperationError, "The requested device operation is not supported or prohibited by the running operating system." }, + { QextSerialPort::TimeoutError, "A timeout error occurred." }, + { QextSerialPort::UnknownError, "An unidentified error occurred." } }; +#endif PX4Bootloader::PX4Bootloader(QObject *parent) : QObject(parent) @@ -99,9 +103,11 @@ PX4Bootloader::PX4Bootloader(QObject *parent) : } -/// @brief Translate a QSerialPort::SerialPortError code into a string. +/// @brief Translate a QextSerialPort::SerialPortError code into a string. const char* PX4Bootloader::_serialPortErrorString(int error) { + Q_UNUSED(error); +#if 0 Again: for (size_t i=0; ibytesToWrite() > 50) { - int bump = 0; - bump++; - } - qint64 bytesWritten = port->write((const char*)data, maxSize); if (bytesWritten == -1) { _errorString = tr("Write failed: %1").arg(port->errorString()); @@ -136,39 +139,36 @@ bool PX4Bootloader::write(QSerialPort* port, const uint8_t* data, qint64 maxSize qWarning() << _errorString; return false; } - if (!port->waitForBytesWritten(1000)) { - _errorString = tr("Timeout waiting for write"); - qWarning() << _errorString; - return false; - } return true; } -bool PX4Bootloader::write(QSerialPort* port, const uint8_t byte) +bool PX4Bootloader::write(QextSerialPort* port, const uint8_t byte) { uint8_t buf[1] = { byte }; return write(port, buf, 1); } -bool PX4Bootloader::read(QSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout) +bool PX4Bootloader::read(QextSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout) { - qint64 bytesToRead = 0; - - while (bytesToRead < maxSize) { - if (port->bytesAvailable() == 0) { - if (!port->waitForReadyRead(readTimeout)) { - _errorString = tr("Timeout waiting for byte to be available"); + qint64 bytesAlreadyRead = 0; + + while (bytesAlreadyRead < maxSize) { + QTime timeout; + timeout.start(); + while (port->bytesAvailable() < 1) { + if (timeout.elapsed() > readTimeout) { + _errorString = tr("Timeout waiting for bytes to be available"); if (warnOnError) { qWarning() << _errorString; } return false; } - Q_ASSERT(port->bytesAvailable() != 0); + QGC::SLEEP::usleep(100); } qint64 bytesRead; - bytesRead = port->read((char*)&data[bytesToRead], maxSize); + bytesRead = port->read((char*)&data[bytesAlreadyRead], maxSize); if (bytesRead == -1) { _errorString = tr("Read failed: Could not read 1 byte, error: %1").arg(port->errorString()); @@ -178,14 +178,14 @@ bool PX4Bootloader::read(QSerialPort* port, uint8_t* data, qint64 maxSize, bool return false; } else { Q_ASSERT(bytesRead != 0); - bytesToRead += bytesRead; + bytesAlreadyRead += bytesRead; } } return true; } -bool PX4Bootloader::getCommandResponse(QSerialPort* port, bool warnOnError, int responseTimeout) +bool PX4Bootloader::getCommandResponse(QextSerialPort* port, bool warnOnError, int responseTimeout) { uint8_t response[2]; @@ -217,30 +217,32 @@ bool PX4Bootloader::getCommandResponse(QSerialPort* port, bool warnOnError, int return true; } -bool PX4Bootloader::getBoardInfo(QSerialPort* port, uint8_t param, uint32_t& value) +bool PX4Bootloader::getBoardInfo(QextSerialPort* port, uint8_t param, uint32_t& value) { uint8_t buf[3] = { PROTO_GET_DEVICE, param, PROTO_EOC }; if (!write(port, buf, sizeof(buf))) { return false; } + port->flush(); if (!read(port, (uint8_t*)&value, sizeof(value), warnOnError)) { return false; } return getCommandResponse(port, warnOnError); } -bool PX4Bootloader::sendCommand(QSerialPort* port, const uint8_t cmd, bool warnOnError, int responseTimeout) +bool PX4Bootloader::sendCommand(QextSerialPort* port, const uint8_t cmd, bool warnOnError, int responseTimeout) { uint8_t buf[2] = { cmd, PROTO_EOC }; if (!write(port, buf, 2)) { return false; } + port->flush(); return getCommandResponse(port, warnOnError, responseTimeout); } -bool PX4Bootloader::erase(QSerialPort* port) +bool PX4Bootloader::erase(QextSerialPort* port) { // Erase is slow, need larger timeout if (!sendCommand(port, PROTO_CHIP_ERASE, warnOnError, _eraseTimeout)) { @@ -252,7 +254,7 @@ bool PX4Bootloader::erase(QSerialPort* port) return true; } -bool PX4Bootloader::program(QSerialPort* port, const QString& firmwareFilename) +bool PX4Bootloader::program(QextSerialPort* port, const QString& firmwareFilename) { QFile firmwareFile(firmwareFilename); if (!firmwareFile.open(QIODevice::ReadOnly)) { @@ -285,11 +287,20 @@ bool PX4Bootloader::program(QSerialPort* port, const QString& firmwareFilename) Q_ASSERT(bytesToSend <= 0x8F); - if (!write(port, PROTO_PROG_MULTI) || - !write(port, (uint8_t)bytesToSend) || - !write(port, imageBuf, bytesToSend) || - !write(port, PROTO_EOC) || - !getCommandResponse(port, warnOnError)) { + bool failed = true; + if (write(port, PROTO_PROG_MULTI)) { + if (write(port, (uint8_t)bytesToSend)) { + if (write(port, imageBuf, bytesToSend)) { + if (write(port, PROTO_EOC)) { + port->flush(); + if (getCommandResponse(port, warnOnError)) { + failed = false; + } + } + } + } + } + if (failed) { _errorString = tr("Flash failed: %1").arg(_errorString); qWarning() << _errorString; return false; @@ -314,7 +325,7 @@ bool PX4Bootloader::program(QSerialPort* port, const QString& firmwareFilename) return true; } -bool PX4Bootloader::verify(QSerialPort* port, const QString firmwareFilename) +bool PX4Bootloader::verify(QextSerialPort* port, const QString firmwareFilename) { bool ret; @@ -331,7 +342,7 @@ bool PX4Bootloader::verify(QSerialPort* port, const QString firmwareFilename) /// @brief Verify the flash on bootloader version 2 by reading it back and comparing it against /// the original firmware file. -bool PX4Bootloader::_bootloaderVerifyRev2(QSerialPort* port, const QString firmwareFilename) +bool PX4Bootloader::_bootloaderVerifyRev2(QextSerialPort* port, const QString firmwareFilename) { QFile firmwareFile(firmwareFilename); if (!firmwareFile.open(QIODevice::ReadOnly)) { @@ -368,11 +379,20 @@ bool PX4Bootloader::_bootloaderVerifyRev2(QSerialPort* port, const QString firmw Q_ASSERT(bytesToRead <= 0x8F); - if (!write(port, PROTO_READ_MULTI) || - !write(port, (uint8_t)bytesToRead) || - !write(port, PROTO_EOC) || - !read(port, flashBuf, sizeof(flashBuf), warnOnError) || - !getCommandResponse(port, warnOnError)) { + bool failed = true; + if (write(port, PROTO_READ_MULTI)) { + if (write(port, (uint8_t)bytesToRead)) { + if (write(port, PROTO_EOC)) { + port->flush(); + if (read(port, flashBuf, sizeof(flashBuf), warnOnError)) { + if (getCommandResponse(port, warnOnError)) { + failed = false; + } + } + } + } + } + if (failed) { return false; } @@ -392,16 +412,23 @@ bool PX4Bootloader::_bootloaderVerifyRev2(QSerialPort* port, const QString firmw } /// @Brief Verify the flash on a version 3 or higher bootloader board by comparing CRCs. -bool PX4Bootloader::_bootloaderVerifyRev3(QSerialPort* port) +bool PX4Bootloader::_bootloaderVerifyRev3(QextSerialPort* port) { return true; uint8_t buf[2] = { PROTO_GET_CRC, PROTO_EOC }; quint32 flashCRC; - if (!write(port, buf, 2) || - !read(port, (uint8_t*)&flashCRC, sizeof(flashCRC), warnOnError, _verifyTimeout) || - !getCommandResponse(port, warnOnError)) { + bool failed = true; + if (write(port, buf, 2)) { + port->flush(); + if (read(port, (uint8_t*)&flashCRC, sizeof(flashCRC), warnOnError, _verifyTimeout)) { + if (getCommandResponse(port, warnOnError)) { + failed = false; + } + } + } + if (failed) { return false; } @@ -413,19 +440,19 @@ bool PX4Bootloader::_bootloaderVerifyRev3(QSerialPort* port) return true; } -bool PX4Bootloader::open(QSerialPort* port, const QString portName) +bool PX4Bootloader::open(QextSerialPort* port, const QString portName) { Q_ASSERT(!port->isOpen()); port->setPortName(portName); - port->setBaudRate(QSerialPort::Baud115200); - port->setDataBits(QSerialPort::Data8); - port->setParity(QSerialPort::NoParity); - port->setStopBits(QSerialPort::OneStop); - port->setFlowControl(QSerialPort::NoFlowControl); - - if (!port->open(QIODevice::ReadWrite)) { - _errorString = tr("Open failed on port %1: %2").arg(portName).arg(_serialPortErrorString(port->error())); + port->setBaudRate(BAUD115200); + port->setDataBits(DATA_8); + port->setParity(PAR_NONE); + port->setStopBits(STOP_1); + port->setFlowControl(FLOW_OFF); + + if (!port->open(QIODevice::ReadWrite | QIODevice::Unbuffered)) { + _errorString = tr("Open failed on port %1: %2").arg(portName).arg(port->errorString()); qWarning() << _errorString; return false; } @@ -433,20 +460,13 @@ bool PX4Bootloader::open(QSerialPort* port, const QString portName) return true; } -bool PX4Bootloader::sync(QSerialPort* port) +bool PX4Bootloader::sync(QextSerialPort* port) { - // Drain out any remaining input or output from the port - if (!port->clear()) { - _errorString = tr("Unable to clear port"); - qWarning() << _errorString; - return false; - } - // Send sync command return sendCommand(port, PROTO_GET_SYNC, noWarnOnError); } -bool PX4Bootloader::getBoardInfo(QSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize) +bool PX4Bootloader::getBoardInfo(QextSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize) { if (!getBoardInfo(port, INFO_BL_REV, _bootloaderVersion)) { @@ -482,7 +502,7 @@ Error: return false; } -bool PX4Bootloader::sendBootloaderReboot(QSerialPort* port) +bool PX4Bootloader::sendBootloaderReboot(QextSerialPort* port) { return write(port, PROTO_BOOT) && write(port, PROTO_EOC); } diff --git a/src/ui/px4_configuration/PX4Bootloader.h b/src/ui/px4_configuration/PX4Bootloader.h index 566bc0018..78dfa570b 100644 --- a/src/ui/px4_configuration/PX4Bootloader.h +++ b/src/ui/px4_configuration/PX4Bootloader.h @@ -28,7 +28,7 @@ #ifndef PX4Bootloader_H #define PX4Bootloader_H -#include +#include "qextserialport.h" #include @@ -52,56 +52,56 @@ public: /// @param data Bytes to write /// @param maxSize Number of bytes to write /// @return true: success - bool write(QSerialPort* port, const uint8_t* data, qint64 maxSize); - bool write(QSerialPort* port, const uint8_t byte); + bool write(QextSerialPort* port, const uint8_t* data, qint64 maxSize); + bool write(QextSerialPort* port, const uint8_t byte); /// @brief Read a set of bytes from the port /// @param data Read bytes into this buffer /// @param maxSize Number of bytes to read /// @param warnOnError true: Log error using qWarning /// @param readTimeout Msecs to wait for bytes to become available on port - bool read(QSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout = _readTimout); + bool read(QextSerialPort* port, uint8_t* data, qint64 maxSize, bool warnOnError, int readTimeout = _readTimout); /// @brief Read a PROTO_SYNC command response from the bootloader /// @param responseTimeout Msecs to wait for response bytes to become available on port - bool getCommandResponse(QSerialPort* port, bool warnOnError, const int responseTimeout = _responseTimeout); + bool getCommandResponse(QextSerialPort* port, bool warnOnError, const int responseTimeout = _responseTimeout); /// @brief Send a PROTO_GET_DEVICE command to retrieve a value from the bootloader /// @param param Value to retrieve using INFO_BOARD_* enums /// @param value Returned value - bool getBoardInfo(QSerialPort* port, uint8_t param, uint32_t& value); + bool getBoardInfo(QextSerialPort* port, uint8_t param, uint32_t& value); /// @brief Send a command to the bootloader /// @param cmd Command to send using PROTO_* enums /// @return true: Command sent and valid sync response returned - bool sendCommand(QSerialPort* port, uint8_t cmd, bool warnOnError, int responseTimeout = _responseTimeout); + bool sendCommand(QextSerialPort* port, uint8_t cmd, bool warnOnError, int responseTimeout = _responseTimeout); /// @brief Program the board with the specified firmware - bool program(QSerialPort* port, const QString& firmwareFilename); + bool program(QextSerialPort* port, const QString& firmwareFilename); /// @brief Verify the board flash. How it works depend on bootloader rev /// Rev 2: Read the flash back and compare it against the firmware file /// Rev 3: Compare CRCs for flash and file - bool verify(QSerialPort* port, const QString firmwareFilename); + bool verify(QextSerialPort* port, const QString firmwareFilename); /// @brief Read a PROTO_SYNC response from the bootloader /// @return true: Valid sync response was received - bool sync(QSerialPort* port); + bool sync(QextSerialPort* port); /// @brief Retrieve a set of board info from the bootloader /// @param bootloaderVersion Returned INFO_BL_REV /// @param boardID Returned INFO_BOARD_ID /// @param flashSize Returned INFO_FLASH_SIZE - bool getBoardInfo(QSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize); + bool getBoardInfo(QextSerialPort* port, uint32_t& bootloaderVersion, uint32_t& boardID, uint32_t& flashSize); /// @brief Opens a port to the bootloader - bool open(QSerialPort* port, const QString portName); + bool open(QextSerialPort* port, const QString portName); /// @brief Sends a PROTO_REBOOT command to the bootloader - bool sendBootloaderReboot(QSerialPort* port); + bool sendBootloaderReboot(QextSerialPort* port); /// @brief Sends a PROTO_ERASE command to the bootlader - bool erase(QSerialPort* port); + bool erase(QextSerialPort* port); signals: /// @brief Signals progress indicator for long running bootloader utility routines @@ -148,8 +148,8 @@ private: bool _findBootloader(void); bool _downloadFirmware(void); - bool _bootloaderVerifyRev2(QSerialPort* port, const QString firmwareFilename); - bool _bootloaderVerifyRev3(QSerialPort* port); + bool _bootloaderVerifyRev2(QextSerialPort* port, const QString firmwareFilename); + bool _bootloaderVerifyRev3(QextSerialPort* port); const char* _serialPortErrorString(int error); @@ -166,7 +166,7 @@ private: QString _errorString; ///< Last error - static const struct serialPortErrorString _rgSerialPortErrors[14]; ///< Translation of QSerialPort::SerialPortError into string + static const struct serialPortErrorString _rgSerialPortErrors[14]; ///< Translation of QextSerialPort::SerialPortError into string static const int _eraseTimeout = 20000; ///< Msecs to wait for response from erase command static const int _rebootTimeout = 10000; ///< Msecs to wait for reboot command to cause serial port to disconnect diff --git a/src/ui/px4_configuration/PX4FirmwareUpgrade.cc b/src/ui/px4_configuration/PX4FirmwareUpgrade.cc index 47f001456..11b126434 100644 --- a/src/ui/px4_configuration/PX4FirmwareUpgrade.cc +++ b/src/ui/px4_configuration/PX4FirmwareUpgrade.cc @@ -91,7 +91,8 @@ const PX4FirmwareUpgrade::stateMachineEntry* PX4FirmwareUpgrade::_getStateMachin static const char* msgFirmwareBoardEraseFailed = "Board erase failed."; static const char* msgFirmwareBoardFlashing = "Flashing new firmware onto board..."; static const char* msgFirmwareBoardFlashError = "A failure has occured while flashing the new firmware to your board. " - "This has left the board in an inconsistent state. " + "This has left the board in an inconsistent state.\n\n" + "There currently is an known issue which does not yet have a fix which may cause this.\n\n" "You should click 'Try Again' to attempt the upgrade process again."; static const char* msgFirmwareBoardVerifying = "Verifying firmware on board..."; static const char* msgFirmwareBoardVerifyError = "Verification of flash memory on board failed. " diff --git a/src/ui/px4_configuration/PX4FirmwareUpgrade.h b/src/ui/px4_configuration/PX4FirmwareUpgrade.h index 0a7361dd4..6ab2f8280 100644 --- a/src/ui/px4_configuration/PX4FirmwareUpgrade.h +++ b/src/ui/px4_configuration/PX4FirmwareUpgrade.h @@ -30,11 +30,12 @@ #include #include -#include #include #include #include +#include "qextserialport.h" + #include #include "PX4FirmwareUpgradeThread.h" diff --git a/src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc b/src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc index 2a9b7ff03..168f2ef22 100644 --- a/src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc +++ b/src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc @@ -99,7 +99,7 @@ void PX4FirmwareUpgradeThreadWorker::_findBoardOnce(void) qDebug() << "\tvendor ID:" << info.vendorIdentifier(); qDebug() << "\tproduct ID:" << info.productIdentifier(); - portName = info.portName(); + portName = info.systemLocation(); portDescription = info.description(); #ifdef Q_OS_WIN @@ -134,7 +134,7 @@ void PX4FirmwareUpgradeThreadWorker::_findBootloaderOnce(void) uint32_t bootloaderVersion, boardID, flashSize; - _bootloaderPort = new QSerialPort; + _bootloaderPort = new QextSerialPort(QextSerialPort::Polling); Q_CHECK_PTR(_bootloaderPort); if (_bootloader->open(_bootloaderPort, _portName)) { @@ -149,7 +149,7 @@ void PX4FirmwareUpgradeThreadWorker::_findBootloaderOnce(void) _bootloaderPort->close(); _bootloaderPort->deleteLater(); _bootloaderPort = NULL; - qDebug() << "Bootloader error:" << _bootloader->errorString(); + qDebug() << "Bootloader Get Board Info error:" << _bootloader->errorString(); emit error(commandBootloader, _bootloader->errorString()); return; } diff --git a/src/ui/px4_configuration/PX4FirmwareUpgradeThread.h b/src/ui/px4_configuration/PX4FirmwareUpgradeThread.h index 59a7f4a68..141c13092 100644 --- a/src/ui/px4_configuration/PX4FirmwareUpgradeThread.h +++ b/src/ui/px4_configuration/PX4FirmwareUpgradeThread.h @@ -29,11 +29,12 @@ #define PX4FirmwareUpgradeThread_H #include -#include #include #include #include +#include "qextserialport.h" + #include #include "PX4Bootloader.h" @@ -85,7 +86,7 @@ private slots: private: PX4Bootloader* _bootloader; - QSerialPort* _bootloaderPort; + QextSerialPort* _bootloaderPort; QTimer* _timerTimeout; QTimer* _timerRetry; QTime _elapsed; -- 2.22.0