diff --git a/libs/qextserialport/.gitignore b/libs/qextserialport/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e83cf5f9a98448729eac012a11f4cba0aa4cdb37 --- /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 0000000000000000000000000000000000000000..a632293d652c01cf7709f550938937f0a309a55c --- /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 0000000000000000000000000000000000000000..a8056fc1bdbd41834a8ad789d50809028730998f --- /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 0000000000000000000000000000000000000000..3a9603e62f5dea0d36b2d5345c64664e7d2b9833 --- /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 0000000000000000000000000000000000000000..5d1babb23b35301638bb5b8ebed641d7dbb7f528 --- /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 0000000000000000000000000000000000000000..eab0ff8fc807f43fc0edeae42f4d00cf1d756851 --- /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 Binary files /dev/null and b/libs/qextserialport/doc/examples/images/uartassistant.png differ diff --git a/libs/qextserialport/doc/examples/qespta.qdoc b/libs/qextserialport/doc/examples/qespta.qdoc new file mode 100755 index 0000000000000000000000000000000000000000..035ab294d1a3ea5ae61032730aa162b2699888c4 --- /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 0000000000000000000000000000000000000000..7ad6b8efa8292b02cfd9b02404ecdc6ea7f06288 --- /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 0000000000000000000000000000000000000000..9c95f4c82404537502a11df0c40a2acaa7aa0e94 --- /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 0000000000000000000000000000000000000000..5e7abfd981cbe50f95591c7756851e7acf4e5ab2 --- /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 0000000000000000000000000000000000000000..e97b883e689fcd040d2aa306594b223d3a8da35b --- /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 0000000000000000000000000000000000000000..0a5959f9ebd903940e4266f73f358e0548ca6f68 --- /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 0000000000000000000000000000000000000000..96557d0d1d806b492f56c240c55d20691d8d2d9b --- /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 0000000000000000000000000000000000000000..e0a6e8cf9eb90876866fc40be488326e0678210e --- /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 0000000000000000000000000000000000000000..51df8f1fcadec606cf0a36b7106282c778fe5165 --- /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 0000000000000000000000000000000000000000..c7d06f5da01460b0752da6cb3a1ef3da7a02e1a7 --- /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 0000000000000000000000000000000000000000..f8e1b6f26fa7d093ea647880ee2e8fe2e37a0f4a --- /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 0000000000000000000000000000000000000000..dd92d23fb97d6da5f139194e537bd507f6921382 --- /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 0000000000000000000000000000000000000000..c7faf782e2cc4fae5011fc2f42c1da4667af2d03 --- /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 0000000000000000000000000000000000000000..fa3dc7ec269064de81de97d9b61f31e176a66599 --- /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 0000000000000000000000000000000000000000..91cffd4f048a07ffed95429acf3b1292ec503e43 --- /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 0000000000000000000000000000000000000000..732c206b637bb11e8be469ac38d5c3722fd789b2 --- /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 0000000000000000000000000000000000000000..183382be9604031afbad43fc325c53e0da8f7735 --- /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 0000000000000000000000000000000000000000..66a0a8c62360a3e79676954ebdca0bd41dbf9b35 --- /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 0000000000000000000000000000000000000000..b26cfafd4d21593d95d1983d6d6bacf685c74a44 --- /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 0000000000000000000000000000000000000000..edc23a3d4f1afdf393c0cd86569daf3512b407f3 --- /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 0000000000000000000000000000000000000000..f232861a6560be05d0ad050b6dafe8d130ef9978 --- /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 0000000000000000000000000000000000000000..bf271c45ab0394ca1369dfdc036f017440860d42 --- /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 0000000000000000000000000000000000000000..6175ab31f53904e926821e2ae2a90cf3172ee41f --- /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 0000000000000000000000000000000000000000..7e479787c4a5e850f96c10b46aaf2346ecf0dbca --- /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 0000000000000000000000000000000000000000..8f7e6535eb8778301eff20801c3425d149635da7 --- /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 0000000000000000000000000000000000000000..6255e48ff9450f2b486f8014d9d20a8981aec90c --- /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 0000000000000000000000000000000000000000..54225d60d4a289845c0c57e131b8a8f224cadc6b --- /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 0000000000000000000000000000000000000000..7cace73cbc3a6e994c2024765e0b6aa123ad2e7f --- /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 0000000000000000000000000000000000000000..5e73141a811f745b8f40b7f0cd5aa1b1f17afc1a --- /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 0000000000000000000000000000000000000000..aa6056bf77d7e23e9026afc1c6cd2da0d512d3cd --- /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 0000000000000000000000000000000000000000..e1e8a43adc39c791f16b6cbe105b645d7bba5843 --- /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 0000000000000000000000000000000000000000..ec1491a74741f39ce98c53e34b170c2df8199d3d --- /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 0000000000000000000000000000000000000000..99f515d58590848998e3c7377a4ed05b90f4ae4f --- /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 0000000000000000000000000000000000000000..a57dfe63974c887f1138fc7adb3092ecb1f59154 --- /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 0000000000000000000000000000000000000000..2dd03570cb2f7596097f8e10da2af14c5a27be45 --- /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 0000000000000000000000000000000000000000..7bfebad5fbd75da36cc643966cd511857caafa22 --- /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 0000000000000000000000000000000000000000..80a4ad426158b883e7efd607072a14767c909cbd --- /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 0000000000000000000000000000000000000000..30b656c4f3593a7354a17a7f74141447fb02f77d --- /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 0000000000000000000000000000000000000000..119bef86840c8a047e4a88b253a245381e271a79 --- /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 0000000000000000000000000000000000000000..5334e94b2c4cec39a5b16cb5067b2ec415bf27a1 --- /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 0000000000000000000000000000000000000000..461d56f646ecaf78fdde2e63cbe02caa3712ffc4 --- /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 0000000000000000000000000000000000000000..824d455420a6d69751936d3e2570c7218074104f --- /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 0000000000000000000000000000000000000000..d278a17e9dccb54a59c33bf1b46ade2a7fb93a33 --- /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 0000000000000000000000000000000000000000..4c02a206dcf0d7fb3fca8858fa0d7b94154f3fb5 --- /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 0000000000000000000000000000000000000000..4dfd97ac3dce10d4d939b0be0e387397085bbfb3 --- /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 c7057995c409be8d3c03cf4d46182868d1ac8699..0c0b7088e623a341c164d3efed2af28583c471cf 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 51c6d3310b4ae9b85269879f4ac0a5b711a887f9..2014f308fe30d34b8a57aae196e97b18fbec948a 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,55 +78,14 @@ static quint32 crc32(const uint8_t *src, unsigned len, unsigned state) return state; } -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." } -}; - PX4Bootloader::PX4Bootloader(QObject *parent) : QObject(parent) { } -/// @brief Translate a QSerialPort::SerialPortError code into a string. -const char* PX4Bootloader::_serialPortErrorString(int error) -{ -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 +97,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 +136,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 +175,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 +212,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,12 +245,21 @@ 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)) { - _errorString = tr("Flash failed: %1").arg(_errorString); + 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 at address 0x%2").arg(_errorString).arg(bytesSent, 8, 16, QLatin1Char('0')); qWarning() << _errorString; return false; } @@ -314,7 +283,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 +300,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,17 +337,28 @@ 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) { + _errorString = tr("Verify failed: %1 at address: 0x%2").arg(_errorString).arg(bytesVerified, 8, 16, QLatin1Char('0')); + qWarning() << _errorString; return false; } for (int i=0; iflush(); + if (read(port, (uint8_t*)&flashCRC, sizeof(flashCRC), warnOnError, _verifyTimeout)) { + if (getCommandResponse(port, warnOnError)) { + failed = false; + } + } + } + if (failed) { return false; } @@ -413,19 +400,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 +420,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 +462,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 566bc001832c1e2c2ca7d12d7cc14a754f37a318..aec3c78e6bb0e459aa1f929bfd6f69c669c6ebf3 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 @@ -138,20 +138,13 @@ private: INFO_FLASH_SIZE = 4, ///< max firmware size in bytes PROG_MULTI_MAX = 32, ///< write size for PROTO_PROG_MULTI, must be multiple of 4 - READ_MULTI_MAX = 64 ///< read size for PROTO_READ_MULTI, must be multiple of 4 - }; - - struct serialPortErrorString { - int error; - const char* errorString; + READ_MULTI_MAX = 32 ///< read size for PROTO_READ_MULTI, must be multiple of 4 }; bool _findBootloader(void); bool _downloadFirmware(void); - bool _bootloaderVerifyRev2(QSerialPort* port, const QString firmwareFilename); - bool _bootloaderVerifyRev3(QSerialPort* port); - - const char* _serialPortErrorString(int error); + bool _bootloaderVerifyRev2(QextSerialPort* port, const QString firmwareFilename); + bool _bootloaderVerifyRev3(QextSerialPort* port); static const int _boardIDPX4FMUV1 = 5; ///< Board ID for PX4 V1 board static const int _boardIDPX4FMUV2 = 9; ///< Board ID for PX4 V2 board @@ -166,8 +159,6 @@ private: QString _errorString; ///< Last error - static const struct serialPortErrorString _rgSerialPortErrors[14]; ///< Translation of QSerialPort::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 static const int _verifyTimeout = 5000; ///< Msecs to wait for response to PROTO_GET_CRC command diff --git a/src/ui/px4_configuration/PX4FirmwareUpgrade.cc b/src/ui/px4_configuration/PX4FirmwareUpgrade.cc index 47f001456e7b56e443a00a9585df294d9cd77153..11b126434b48a8956cff93b3357c19bfba9f0750 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 0a7361dd4a3ab4eac18728fe9a9080c3d6eec092..6ab2f828067ba2d63fd60953e8f018d5aa62f10a 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 2a9b7ff032fda0bf13328447a1a5373fdf5d111a..168f2ef22fc98f502938827d1eb0ee822b0956f5 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 59a7f4a6832de43a1b8e433e4021c34b41002ea1..141c13092867ea5fabedfd8d03f75b3df9fbd76a 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;