[89] | 1 |
|
---|
| 2 | #ifndef _QEXTSERIALPORT_H_
|
---|
| 3 | #define _QEXTSERIALPORT_H_
|
---|
| 4 |
|
---|
| 5 | #include "qextserialport_global.h"
|
---|
| 6 |
|
---|
| 7 | /*if all warning messages are turned off, flag portability warnings to be turned off as well*/
|
---|
| 8 | #ifdef _TTY_NOWARN_
|
---|
| 9 | #define _TTY_NOWARN_PORT_
|
---|
| 10 | #endif
|
---|
| 11 |
|
---|
| 12 | /*macros for warning and debug messages*/
|
---|
| 13 | #ifdef _TTY_NOWARN_PORT_
|
---|
| 14 | #define TTY_PORTABILITY_WARNING(s)
|
---|
| 15 | #else
|
---|
| 16 | #define TTY_PORTABILITY_WARNING(s) qWarning(s)
|
---|
| 17 | #endif /*_TTY_NOWARN_PORT_*/
|
---|
| 18 | #ifdef _TTY_NOWARN_
|
---|
| 19 | #define TTY_WARNING(s)
|
---|
| 20 | #else
|
---|
| 21 | #define TTY_WARNING(s) qWarning(s)
|
---|
| 22 | #endif /*_TTY_NOWARN_*/
|
---|
| 23 |
|
---|
| 24 |
|
---|
| 25 | /*line status constants*/
|
---|
| 26 | #define LS_CTS 0x01
|
---|
| 27 | #define LS_DSR 0x02
|
---|
| 28 | #define LS_DCD 0x04
|
---|
| 29 | #define LS_RI 0x08
|
---|
| 30 | #define LS_RTS 0x10
|
---|
| 31 | #define LS_DTR 0x20
|
---|
| 32 | #define LS_ST 0x40
|
---|
| 33 | #define LS_SR 0x80
|
---|
| 34 |
|
---|
| 35 | /*error constants*/
|
---|
| 36 | #define E_NO_ERROR 0
|
---|
| 37 | #define E_INVALID_FD 1
|
---|
| 38 | #define E_NO_MEMORY 2
|
---|
| 39 | #define E_CAUGHT_NON_BLOCKED_SIGNAL 3
|
---|
| 40 | #define E_PORT_TIMEOUT 4
|
---|
| 41 | #define E_INVALID_DEVICE 5
|
---|
| 42 | #define E_BREAK_CONDITION 6
|
---|
| 43 | #define E_FRAMING_ERROR 7
|
---|
| 44 | #define E_IO_ERROR 8
|
---|
| 45 | #define E_BUFFER_OVERRUN 9
|
---|
| 46 | #define E_RECEIVE_OVERFLOW 10
|
---|
| 47 | #define E_RECEIVE_PARITY_ERROR 11
|
---|
| 48 | #define E_TRANSMIT_OVERFLOW 12
|
---|
| 49 | #define E_READ_FAILED 13
|
---|
| 50 | #define E_WRITE_FAILED 14
|
---|
| 51 | #define E_FILE_NOT_FOUND 15
|
---|
| 52 |
|
---|
| 53 | enum BaudRateType
|
---|
| 54 | {
|
---|
| 55 | BAUD50, //POSIX ONLY
|
---|
| 56 | BAUD75, //POSIX ONLY
|
---|
| 57 | BAUD110,
|
---|
| 58 | BAUD134, //POSIX ONLY
|
---|
| 59 | BAUD150, //POSIX ONLY
|
---|
| 60 | BAUD200, //POSIX ONLY
|
---|
| 61 | BAUD300,
|
---|
| 62 | BAUD600,
|
---|
| 63 | BAUD1200,
|
---|
| 64 | BAUD1800, //POSIX ONLY
|
---|
| 65 | BAUD2400,
|
---|
| 66 | BAUD4800,
|
---|
| 67 | BAUD9600,
|
---|
| 68 | BAUD14400, //WINDOWS ONLY
|
---|
| 69 | BAUD19200,
|
---|
| 70 | BAUD38400,
|
---|
| 71 | BAUD56000, //WINDOWS ONLY
|
---|
| 72 | BAUD57600,
|
---|
| 73 | BAUD76800, //POSIX ONLY
|
---|
| 74 | BAUD115200,
|
---|
| 75 | BAUD128000, //WINDOWS ONLY
|
---|
| 76 | BAUD256000 //WINDOWS ONLY
|
---|
| 77 | };
|
---|
| 78 |
|
---|
| 79 | enum DataBitsType
|
---|
| 80 | {
|
---|
| 81 | DATA_5,
|
---|
| 82 | DATA_6,
|
---|
| 83 | DATA_7,
|
---|
| 84 | DATA_8
|
---|
| 85 | };
|
---|
| 86 |
|
---|
| 87 | enum ParityType
|
---|
| 88 | {
|
---|
| 89 | PAR_NONE,
|
---|
| 90 | PAR_ODD,
|
---|
| 91 | PAR_EVEN,
|
---|
| 92 | PAR_MARK, //WINDOWS ONLY
|
---|
| 93 | PAR_SPACE
|
---|
| 94 | };
|
---|
| 95 |
|
---|
| 96 | enum StopBitsType
|
---|
| 97 | {
|
---|
| 98 | STOP_1,
|
---|
| 99 | STOP_1_5, //WINDOWS ONLY
|
---|
| 100 | STOP_2
|
---|
| 101 | };
|
---|
| 102 |
|
---|
| 103 | enum FlowType
|
---|
| 104 | {
|
---|
| 105 | FLOW_OFF,
|
---|
| 106 | FLOW_HARDWARE,
|
---|
| 107 | FLOW_XONXOFF
|
---|
| 108 | };
|
---|
| 109 |
|
---|
| 110 | /**
|
---|
| 111 | * structure to contain port settings
|
---|
| 112 | */
|
---|
| 113 | struct PortSettings
|
---|
| 114 | {
|
---|
| 115 | BaudRateType BaudRate;
|
---|
| 116 | DataBitsType DataBits;
|
---|
| 117 | ParityType Parity;
|
---|
| 118 | StopBitsType StopBits;
|
---|
| 119 | FlowType FlowControl;
|
---|
| 120 | long Timeout_Millisec;
|
---|
| 121 | };
|
---|
| 122 |
|
---|
| 123 | #include <QIODevice>
|
---|
| 124 | #include <QMutex>
|
---|
| 125 | #ifdef Q_OS_UNIX
|
---|
| 126 | #include <stdio.h>
|
---|
| 127 | #include <termios.h>
|
---|
| 128 | #include <errno.h>
|
---|
| 129 | #include <unistd.h>
|
---|
| 130 | #include <sys/time.h>
|
---|
| 131 | #include <sys/ioctl.h>
|
---|
| 132 | #include <sys/select.h>
|
---|
| 133 | #include <QSocketNotifier>
|
---|
| 134 | #elif (defined Q_OS_WIN)
|
---|
| 135 | #include <windows.h>
|
---|
| 136 | #include <QThread>
|
---|
| 137 | #include <QReadWriteLock>
|
---|
| 138 | #include <QtCore/private/qwineventnotifier_p.h>
|
---|
| 139 | #endif
|
---|
| 140 |
|
---|
| 141 | /*!
|
---|
| 142 | Encapsulates a serial port on both POSIX and Windows systems.
|
---|
| 143 |
|
---|
| 144 | \note
|
---|
| 145 | Be sure to check the full list of members, as QIODevice provides quite a lot of
|
---|
| 146 | functionality for QextSerialPort.
|
---|
| 147 |
|
---|
| 148 | \section Usage
|
---|
| 149 | QextSerialPort offers both a polling and event driven API. Event driven is typically easier
|
---|
| 150 | to use, since you never have to worry about checking for new data.
|
---|
| 151 |
|
---|
| 152 | \b Example
|
---|
| 153 | \code
|
---|
| 154 | QextSerialPort* port = new QextSerialPort("COM1", QextSerialPort::EventDriven);
|
---|
| 155 | connect(port, SIGNAL(readyRead()), myClass, SLOT(onDataAvailable()));
|
---|
| 156 | port->open();
|
---|
| 157 |
|
---|
| 158 | void MyClass::onDataAvailable() {
|
---|
| 159 | int avail = port->bytesAvailable();
|
---|
| 160 | if( avail > 0 ) {
|
---|
| 161 | QByteArray usbdata;
|
---|
| 162 | usbdata.resize(avail);
|
---|
| 163 | int read = port->read(usbdata.data(), usbdata.size());
|
---|
| 164 | if( read > 0 ) {
|
---|
| 165 | processNewData(usbdata);
|
---|
| 166 | }
|
---|
| 167 | }
|
---|
| 168 | }
|
---|
| 169 | \endcode
|
---|
| 170 |
|
---|
| 171 | \section Compatibility
|
---|
| 172 | The user will be notified of errors and possible portability conflicts at run-time
|
---|
| 173 | by default - this behavior can be turned off by defining _TTY_NOWARN_
|
---|
| 174 | (to turn off all warnings) or _TTY_NOWARN_PORT_ (to turn off portability warnings) in the project.
|
---|
| 175 |
|
---|
| 176 | On Windows NT/2000/XP this class uses Win32 serial port functions by default. The user may
|
---|
| 177 | select POSIX behavior under NT, 2000, or XP ONLY by defining Q_OS_UNIX in the project.
|
---|
| 178 | No guarantees are made as to the quality of POSIX support under NT/2000 however.
|
---|
| 179 |
|
---|
| 180 | \author Stefan Sander, Michal Policht, Brandon Fosdick, Liam Staskawicz
|
---|
| 181 | */
|
---|
| 182 | class QEXTSERIALPORT_EXPORT QextSerialPort: public QIODevice
|
---|
| 183 | {
|
---|
| 184 | Q_OBJECT
|
---|
| 185 | public:
|
---|
| 186 | enum QueryMode {
|
---|
| 187 | Polling,
|
---|
| 188 | EventDriven
|
---|
| 189 | };
|
---|
| 190 |
|
---|
| 191 | QextSerialPort(QueryMode mode = EventDriven);
|
---|
| 192 | QextSerialPort(const QString & name, QueryMode mode = EventDriven);
|
---|
| 193 | QextSerialPort(PortSettings const& s, QueryMode mode = EventDriven);
|
---|
| 194 | QextSerialPort(const QString & name, PortSettings const& s, QueryMode mode = EventDriven);
|
---|
| 195 | ~QextSerialPort();
|
---|
| 196 |
|
---|
| 197 | void setPortName(const QString & name);
|
---|
| 198 | QString portName() const;
|
---|
| 199 |
|
---|
| 200 | /**!
|
---|
| 201 | * Get query mode.
|
---|
| 202 | * \return query mode.
|
---|
| 203 | */
|
---|
| 204 | inline QueryMode queryMode() const { return _queryMode; }
|
---|
| 205 |
|
---|
| 206 | /*!
|
---|
| 207 | * Set desired serial communication handling style. You may choose from polling
|
---|
| 208 | * or event driven approach. This function does nothing when port is open; to
|
---|
| 209 | * apply changes port must be reopened.
|
---|
| 210 | *
|
---|
| 211 | * In event driven approach read() and write() functions are acting
|
---|
| 212 | * asynchronously. They return immediately and the operation is performed in
|
---|
| 213 | * the background, so they doesn't freeze the calling thread.
|
---|
| 214 | * To determine when operation is finished, QextSerialPort runs separate thread
|
---|
| 215 | * and monitors serial port events. Whenever the event occurs, adequate signal
|
---|
| 216 | * is emitted.
|
---|
| 217 | *
|
---|
| 218 | * When polling is set, read() and write() are acting synchronously. Signals are
|
---|
| 219 | * not working in this mode and some functions may not be available. The advantage
|
---|
| 220 | * of polling is that it generates less overhead due to lack of signals emissions
|
---|
| 221 | * and it doesn't start separate thread to monitor events.
|
---|
| 222 | *
|
---|
| 223 | * Generally event driven approach is more capable and friendly, although some
|
---|
| 224 | * applications may need as low overhead as possible and then polling comes.
|
---|
| 225 | *
|
---|
| 226 | * \param mode query mode.
|
---|
| 227 | */
|
---|
| 228 | void setQueryMode(QueryMode mode);
|
---|
| 229 |
|
---|
| 230 | void setBaudRate(BaudRateType);
|
---|
| 231 | BaudRateType baudRate() const;
|
---|
| 232 |
|
---|
| 233 | void setDataBits(DataBitsType);
|
---|
| 234 | DataBitsType dataBits() const;
|
---|
| 235 |
|
---|
| 236 | void setParity(ParityType);
|
---|
| 237 | ParityType parity() const;
|
---|
| 238 |
|
---|
| 239 | void setStopBits(StopBitsType);
|
---|
| 240 | StopBitsType stopBits() const;
|
---|
| 241 |
|
---|
| 242 | void setFlowControl(FlowType);
|
---|
| 243 | FlowType flowControl() const;
|
---|
| 244 |
|
---|
| 245 | void setTimeout(long);
|
---|
| 246 |
|
---|
| 247 | bool open(OpenMode mode);
|
---|
| 248 | bool isSequential() const;
|
---|
| 249 | void close();
|
---|
| 250 | void flush();
|
---|
| 251 |
|
---|
| 252 | qint64 size() const;
|
---|
| 253 | qint64 bytesAvailable() const;
|
---|
| 254 | QByteArray readAll();
|
---|
| 255 |
|
---|
| 256 | void ungetChar(char c);
|
---|
| 257 |
|
---|
| 258 | ulong lastError() const;
|
---|
| 259 | void translateError(ulong error);
|
---|
| 260 |
|
---|
| 261 | void setDtr(bool set=true);
|
---|
| 262 | void setRts(bool set=true);
|
---|
| 263 | ulong lineStatus();
|
---|
| 264 | QString errorString();
|
---|
| 265 |
|
---|
| 266 | #ifdef Q_OS_WIN
|
---|
| 267 | virtual bool waitForReadyRead(int msecs); ///< @todo implement.
|
---|
| 268 | virtual qint64 bytesToWrite() const;
|
---|
| 269 | static QString fullPortNameWin(const QString & name);
|
---|
| 270 | #endif
|
---|
| 271 |
|
---|
| 272 | protected:
|
---|
| 273 | QMutex* mutex;
|
---|
| 274 | QString port;
|
---|
| 275 | PortSettings Settings;
|
---|
| 276 | ulong lastErr;
|
---|
| 277 | QueryMode _queryMode;
|
---|
| 278 |
|
---|
| 279 | // platform specific members
|
---|
| 280 | #ifdef Q_OS_UNIX
|
---|
| 281 | int fd;
|
---|
| 282 | QSocketNotifier *readNotifier;
|
---|
| 283 | struct termios Posix_CommConfig;
|
---|
| 284 | struct termios old_termios;
|
---|
| 285 | struct timeval Posix_Timeout;
|
---|
| 286 | struct timeval Posix_Copy_Timeout;
|
---|
| 287 | #elif (defined Q_OS_WIN)
|
---|
| 288 | HANDLE Win_Handle;
|
---|
| 289 | OVERLAPPED overlap;
|
---|
| 290 | COMMCONFIG Win_CommConfig;
|
---|
| 291 | COMMTIMEOUTS Win_CommTimeouts;
|
---|
| 292 | QWinEventNotifier *winEventNotifier;
|
---|
| 293 | DWORD eventMask;
|
---|
| 294 | QList<OVERLAPPED*> pendingWrites;
|
---|
| 295 | QReadWriteLock* bytesToWriteLock;
|
---|
| 296 | qint64 _bytesToWrite;
|
---|
| 297 | #endif
|
---|
| 298 |
|
---|
| 299 | void construct(); // common construction
|
---|
| 300 | void platformSpecificDestruct();
|
---|
| 301 | void platformSpecificInit();
|
---|
| 302 | qint64 readData(char * data, qint64 maxSize);
|
---|
| 303 | qint64 writeData(const char * data, qint64 maxSize);
|
---|
| 304 |
|
---|
| 305 | #ifdef Q_OS_WIN
|
---|
| 306 | private slots:
|
---|
| 307 | void onWinEvent(HANDLE h);
|
---|
| 308 | #endif
|
---|
| 309 |
|
---|
| 310 | private:
|
---|
| 311 | Q_DISABLE_COPY(QextSerialPort)
|
---|
| 312 |
|
---|
| 313 | signals:
|
---|
| 314 | // /**
|
---|
| 315 | // * This signal is emitted whenever port settings are updated.
|
---|
| 316 | // * \param valid \p true if settings are valid, \p false otherwise.
|
---|
| 317 | // *
|
---|
| 318 | // * @todo implement.
|
---|
| 319 | // */
|
---|
| 320 | // // void validSettings(bool valid);
|
---|
| 321 |
|
---|
| 322 | /*!
|
---|
| 323 | * This signal is emitted whenever dsr line has changed its state. You may
|
---|
| 324 | * use this signal to check if device is connected.
|
---|
| 325 | * \param status \p true when DSR signal is on, \p false otherwise.
|
---|
| 326 | *
|
---|
| 327 | * \see lineStatus().
|
---|
| 328 | */
|
---|
| 329 | void dsrChanged(bool status);
|
---|
| 330 |
|
---|
| 331 | };
|
---|
| 332 |
|
---|
| 333 | #endif
|
---|