qserialport.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. /****************************************************************************
  2. **
  3. ** This file is part of the Qt Extended Opensource Package.
  4. **
  5. ** Copyright (C) 2009 Trolltech ASA.
  6. **
  7. ** Contact: Qt Extended Information (info@qtextended.org)
  8. **
  9. ** This file may be used under the terms of the GNU General Public License
  10. ** version 2.0 as published by the Free Software Foundation and appearing
  11. ** in the file LICENSE.GPL included in the packaging of this file.
  12. **
  13. ** Please review the following information to ensure GNU General Public
  14. ** Licensing requirements will be met:
  15. ** http://www.fsf.org/licensing/licenses/info/GPLv2.html.
  16. **
  17. **
  18. ****************************************************************************/
  19. #include "qserialport.h"
  20. #include <QDebug>
  21. #include <qsocketnotifier.h>
  22. #include <qtimer.h>
  23. #include <termios.h>
  24. #include <stdio.h>
  25. #include <unistd.h>
  26. #include <errno.h>
  27. #include <sys/types.h>
  28. #include <sys/time.h>
  29. #include <sys/stat.h>
  30. #include <sys/socket.h>
  31. #include <sys/ioctl.h>
  32. #include <sys/select.h>
  33. #include <fcntl.h>
  34. #include <netdb.h>
  35. #include <netinet/in.h>
  36. #include <arpa/inet.h>
  37. #define USE_POSIX_SYSCALLS 1
  38. #define USE_TERMIOS 1
  39. class QSerialPortPrivate
  40. {
  41. public:
  42. QSerialPortPrivate( const QString& device, int rate, bool trackStatus )
  43. {
  44. this->device = device;
  45. this->rate = rate;
  46. this->fd = -1;
  47. this->status = 0;
  48. this->track = trackStatus;
  49. this->isTty = false;
  50. this->dtr = true;
  51. this->rts = true;
  52. this->flowControl = false;
  53. this->keepOpen = true;
  54. this->notifier = 0;
  55. this->timer = 0;
  56. }
  57. ~QSerialPortPrivate()
  58. {
  59. if ( notifier )
  60. delete notifier;
  61. if ( timer )
  62. delete timer;
  63. }
  64. public:
  65. QString device;
  66. int rate;
  67. int fd;
  68. int status;
  69. bool track;
  70. bool isTty;
  71. bool dtr;
  72. bool rts;
  73. bool flowControl;
  74. bool keepOpen;
  75. QSocketNotifier *notifier;
  76. QTimer *timer;
  77. };
  78. /*!
  79. \class QSerialPort
  80. \inpublicgroup QtBaseModule
  81. \brief The QSerialPort class provides a simple serial device interface.
  82. \ingroup io
  83. \ingroup telephony::serial
  84. This class manages a very simple serial device, which is accessed
  85. at a specific baud rate with no parity, 8 data bits, and 1 stop bit.
  86. It is intended for communicating with GSM modems and the like.
  87. The recommended way to create an instance of this class is to
  88. call the QSerialPort::create() method.
  89. \sa QSerialPort::create(), QSerialIODevice
  90. */
  91. /*!
  92. Construct a new serial device handler object for the specified
  93. \a device at the given \a rate. After construction, it is necessary
  94. to call QSerialPort::open() to complete initialization.
  95. If \a trackStatus is true, then the device should attempt to
  96. track changes in DSR, DCD, and CTS. This may require the use
  97. of a regular timeout, which will be detrimental to battery life.
  98. Status tracking should only be enabled when absolutely required.
  99. It isn't required for modems that support GSM 07.10 multiplexing,
  100. as the multiplexing mechanism has its own method of tracking
  101. status changes that does not require the use of a timeout.
  102. The device name is usually something like \c{/dev/ttyS0}, but it can
  103. have the special form \c{sim:hostname}, where \c hostname is the name
  104. of a host running a phone simulator daemon (usually \c localhost).
  105. The phone simulator mode is intended for debugging purposes only.
  106. */
  107. QSerialPort::QSerialPort( const QString& device, int rate, bool trackStatus )
  108. {
  109. d = new QSerialPortPrivate( device, rate, trackStatus );
  110. }
  111. /*!
  112. Destruct this serial device. If the device is currently open,
  113. it will be closed.
  114. */
  115. QSerialPort::~QSerialPort()
  116. {
  117. close();
  118. delete d;
  119. }
  120. /*!
  121. Returns the operating system file descriptor for this serial port,
  122. or -1 if the port is currently closed.
  123. \since 4.3
  124. */
  125. int QSerialPort::fd() const
  126. {
  127. return d->fd;
  128. }
  129. /*!
  130. Opens the serial device with the specified \a mode.
  131. Returns true if the device could be opened; false otherwise.
  132. */
  133. bool QSerialPort::open( OpenMode mode )
  134. {
  135. if ( isOpen() ) {
  136. qDebug() << "QSerialPort already open";
  137. return false;
  138. }
  139. #ifdef USE_POSIX_SYSCALLS
  140. if ( d->device.startsWith( "sim:" ) ) {
  141. // Connect to a phone simulator via a TCP socket.
  142. d->fd = ::socket( AF_INET, SOCK_STREAM, 0 );
  143. if ( d->fd == -1 ) {
  144. qDebug() << "could not open socket";
  145. return false;
  146. }
  147. QString host = d->device.mid( 4 );
  148. int index = host.indexOf(QChar(':'));
  149. int port = 12345;
  150. if ( index != -1 ) {
  151. port = host.mid( index + 1 ).toInt();
  152. host = host.left( index );
  153. }
  154. QByteArray hoststr = host.toLatin1();
  155. const char *lhost = (const char *)hoststr;
  156. struct hostent *ent;
  157. struct sockaddr_in addr;
  158. ::memset( &addr, 0, sizeof( addr ) );
  159. addr.sin_family = AF_INET;
  160. addr.sin_addr.s_addr = inet_addr( lhost );
  161. if ( addr.sin_addr.s_addr == INADDR_NONE ) {
  162. ent = gethostbyname( lhost );
  163. if ( !ent ) {
  164. qDebug() << "could not resolve " << lhost;
  165. ::close( d->fd );
  166. d->fd = -1;
  167. return false;
  168. }
  169. ::memcpy( &(addr.sin_addr), ent->h_addr, sizeof( addr.sin_addr ) );
  170. }
  171. addr.sin_port = htons( (unsigned short)port );
  172. if ( ::connect( d->fd, (struct sockaddr *)&addr, sizeof(addr) ) < 0 ) {
  173. qDebug() << "could not connect to phone simulator at " << lhost;
  174. ::close( d->fd );
  175. d->fd = -1;
  176. return false;
  177. }
  178. ::fcntl( d->fd, F_SETFL, O_NONBLOCK );
  179. d->isTty = 0;
  180. } else {
  181. // Must use a non-blocking open to prevent devices such as
  182. // "/dev/ircomm" and "/dev/ttyS0" from locking up if they
  183. // aren't presently connected to a remote machine.
  184. d->fd = ::open( (const char *)d->device.toLatin1(), O_RDWR | O_NONBLOCK, 0 );
  185. if ( d->fd == -1 ) {
  186. qDebug() << "QSerialPort " << d->device << " cannot be openned";
  187. perror("QSerialPort cannot open");
  188. return false;
  189. }
  190. d->isTty = ::isatty( d->fd );
  191. qDebug() << "Device:" << d->device << "is a tty device:" << (d->isTty ? "True" : "False");
  192. int fdflags;
  193. if ((fdflags = fcntl(d->fd, F_GETFL)) == -1 ||
  194. fcntl(d->fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
  195. {
  196. perror("couldn't reset non-blocking mode");
  197. return false;
  198. }
  199. qDebug() << "NONBLOCK successfully reset";
  200. }
  201. #endif
  202. #ifdef USE_TERMIOS
  203. if ( d->isTty ) {
  204. // Set the serial port attributes.
  205. struct termios t;
  206. speed_t speed;
  207. ::tcgetattr( d->fd, &t );
  208. t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
  209. t.c_cflag |= (CREAD | CLOCAL | CS8);
  210. t.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG);
  211. t.c_iflag &= ~(INPCK | IGNPAR | PARMRK | ISTRIP | IXANY | ICRNL);
  212. t.c_iflag &= ~(IXON | IXOFF);
  213. t.c_oflag &= ~(OPOST | OCRNL);
  214. #ifdef CRTSCTS
  215. if ( d->flowControl )
  216. t.c_cflag |= CRTSCTS;
  217. else
  218. t.c_cflag &= ~CRTSCTS;
  219. #endif
  220. t.c_cc[VMIN] = 0;
  221. t.c_cc[VINTR] = _POSIX_VDISABLE;
  222. t.c_cc[VQUIT] = _POSIX_VDISABLE;
  223. t.c_cc[VSTART] = _POSIX_VDISABLE;
  224. t.c_cc[VSTOP] = _POSIX_VDISABLE;
  225. t.c_cc[VSUSP] = _POSIX_VDISABLE;
  226. switch( d->rate ) {
  227. case 50: speed = B50; break;
  228. case 75: speed = B75; break;
  229. case 110: speed = B110; break;
  230. case 134: speed = B134; break;
  231. case 150: speed = B150; break;
  232. case 200: speed = B200; break;
  233. case 300: speed = B300; break;
  234. case 600: speed = B600; break;
  235. case 1200: speed = B1200; break;
  236. case 1800: speed = B1800; break;
  237. case 2400: speed = B2400; break;
  238. case 4800: speed = B4800; break;
  239. case 9600: speed = B9600; break;
  240. case 19200: speed = B19200; break;
  241. case 38400: speed = B38400; break;
  242. #ifdef B57600
  243. case 57600: speed = B57600; break;
  244. #endif
  245. #ifdef B115200
  246. case 115200: speed = B115200; break;
  247. #endif
  248. #ifdef B230400
  249. case 230400: speed = B230400; break;
  250. #endif
  251. #ifdef B460800
  252. case 460800: speed = B460800; break;
  253. #endif
  254. #ifdef B500000
  255. case 500000: speed = B500000; break;
  256. #endif
  257. #ifdef B576000
  258. case 576000: speed = B576000; break;
  259. #endif
  260. #ifdef B921600
  261. case 921600: speed = B921600; break;
  262. #endif
  263. #ifdef B1000000
  264. case 1000000: speed = B1000000; break;
  265. #endif
  266. #ifdef B1152000
  267. case 1152000: speed = B1152000; break;
  268. #endif
  269. #ifdef B1500000
  270. case 1500000: speed = B1500000; break;
  271. #endif
  272. #ifdef B2000000
  273. case 2000000: speed = B2000000; break;
  274. #endif
  275. #ifdef B2500000
  276. case 2500000: speed = B2500000; break;
  277. #endif
  278. #ifdef B3000000
  279. case 3000000: speed = B3000000; break;
  280. #endif
  281. #ifdef B3500000
  282. case 3500000: speed = B3500000; break;
  283. #endif
  284. #ifdef B4000000
  285. case 4000000: speed = B4000000; break;
  286. #endif
  287. default: speed = 9600; break;
  288. }
  289. ::cfsetispeed( &t, speed );
  290. ::cfsetospeed( &t, speed );
  291. if( ::tcsetattr( d->fd, TCSANOW, &t ) < 0 )
  292. qDebug() << "tcsetattr(" << d->fd << ") errno = " << errno;
  293. int status = TIOCM_DTR | TIOCM_RTS;
  294. ::ioctl( d->fd, TIOCMBIS, &status );
  295. // Use a timer to track status changes. This should be replaced
  296. // with a separate thread that uses TIOCMIWAIT instead.
  297. if ( d->track ) {
  298. ::ioctl( d->fd, TIOCMGET, &(d->status) );
  299. d->timer = new QTimer( this );
  300. connect( d->timer, SIGNAL(timeout()), this, SLOT(statusTimeout()) );
  301. d->timer->start( 500 );
  302. }
  303. }
  304. #endif
  305. #ifdef F_SETFD
  306. // prevent the fd from being passed across a fork/exec.
  307. ::fcntl( d->fd, F_SETFD, FD_CLOEXEC );
  308. #endif
  309. d->notifier = new QSocketNotifier
  310. ( d->fd, QSocketNotifier::Read, this );
  311. connect( d->notifier, SIGNAL(activated(int)),
  312. this, SLOT(internalReadyRead()) );
  313. QIODevice::setOpenMode( mode | QIODevice::Unbuffered );
  314. return true;
  315. }
  316. /*!
  317. Closes the serial device.
  318. */
  319. void QSerialPort::close()
  320. {
  321. if ( d->notifier ) {
  322. d->notifier->deleteLater();
  323. d->notifier = 0;
  324. }
  325. if ( d->timer ) {
  326. delete d->timer;
  327. d->timer = 0;
  328. }
  329. #ifdef USE_POSIX_SYSCALLS
  330. if ( d->fd != -1 ) {
  331. ::close( d->fd );
  332. d->fd = -1;
  333. }
  334. #endif
  335. setOpenMode( NotOpen );
  336. }
  337. /*!
  338. Returns true if able to flush all buffered data to the physical serial device; otherwise returns false.
  339. */
  340. bool QSerialPort::flush()
  341. {
  342. #ifdef USE_TERMIOS
  343. if ( d->fd != -1 && d->isTty ) {
  344. ::tcdrain( d->fd );
  345. }
  346. #endif
  347. return true;
  348. }
  349. /*!
  350. \reimp
  351. */
  352. bool QSerialPort::waitForReadyRead(int msecs)
  353. {
  354. #ifdef USE_POSIX_SYSCALLS
  355. struct timeval tv;
  356. fd_set readSet;
  357. if ( d->fd != -1 ) {
  358. tv.tv_sec = msecs / 1000;
  359. tv.tv_usec = msecs * 1000;
  360. FD_ZERO( &readSet );
  361. FD_SET( d->fd, &readSet );
  362. return ( select( d->fd + 1, &readSet, 0, 0, &tv ) > 0 );
  363. } else {
  364. return false;
  365. }
  366. #else
  367. return false;
  368. #endif
  369. }
  370. /*!
  371. \reimp
  372. */
  373. qint64 QSerialPort::bytesAvailable() const
  374. {
  375. #ifdef USE_POSIX_SYSCALLS
  376. if ( d->fd != -1 ) {
  377. // See comments in Qt4's qsocketlayer_unix.cpp for the reason
  378. // why this ioctl call sequence is a little bizarre in structure.
  379. size_t nbytes = 0;
  380. qint64 available = 0;
  381. if (::ioctl( d->fd, FIONREAD, (char *) &nbytes ) >= 0)
  382. available = (qint64) *((int *) &nbytes);
  383. return available;
  384. } else {
  385. return 0;
  386. }
  387. #else
  388. return 0;
  389. #endif
  390. }
  391. /*!
  392. \reimp
  393. */
  394. qint64 QSerialPort::readData( char *data, qint64 maxlen )
  395. {
  396. #ifdef USE_POSIX_SYSCALLS
  397. int result;
  398. if ( d->fd == -1 ) {
  399. return -1;
  400. }
  401. maxlen = 256;
  402. while ( ( result = ::read( d->fd, data, (int)maxlen ) ) < 0 ) {
  403. if ( errno != EINTR ) {
  404. if ( errno == EWOULDBLOCK ) {
  405. return 0;
  406. }
  407. qDebug() << "read errno = " << errno;
  408. return -1;
  409. }
  410. }
  411. if ( !result && ( !d->isTty || ( !d->keepOpen && !dsr() ) ) ) {
  412. // We've received a close notification. This might happen
  413. // with the phone simulator if it is shut down before Qtopia.
  414. // Don't do this for tty devices because there are some systems
  415. // that return zero when they should be returning EWOULDBLOCK.
  416. qDebug() << "QSerialPort::readData: other end closed the connection" ;
  417. close();
  418. }
  419. return result;
  420. #else
  421. return -1;
  422. #endif
  423. }
  424. /*!
  425. \reimp
  426. */
  427. qint64 QSerialPort::writeData( const char *data, qint64 len )
  428. {
  429. #ifdef USE_POSIX_SYSCALLS
  430. if ( d->fd == -1 ) {
  431. return -1;
  432. }
  433. int result = 0;
  434. int temp;
  435. while ( len > 0 ) {
  436. temp = ::write( d->fd, data, (int)len );
  437. if ( temp >= 0 ) {
  438. result += temp;
  439. len -= (qint64)temp;
  440. data += (uint)temp;
  441. } else if ( errno != EINTR && errno != EWOULDBLOCK ) {
  442. qDebug() << "write(" << d->fd << ") errno = " << errno;
  443. return -1;
  444. }
  445. }
  446. return result;
  447. #else
  448. return (int)len;
  449. #endif
  450. }
  451. /*!
  452. \reimp
  453. */
  454. int QSerialPort::rate() const
  455. {
  456. return d->rate;
  457. }
  458. /*!
  459. Returns the state of CTS/RTS flow control on the serial device.
  460. The default value is false.
  461. \sa setFlowControl()
  462. */
  463. bool QSerialPort::flowControl() const
  464. {
  465. return d->flowControl;
  466. }
  467. /*!
  468. Sets the state of CTS/RTS flow control on the serial device to \a value.
  469. This must be called before QSerialPort::open(). Changes to
  470. the value after opening will be ignored.
  471. \sa flowControl()
  472. */
  473. void QSerialPort::setFlowControl( bool value )
  474. {
  475. d->flowControl = value;
  476. }
  477. /*!
  478. Returns true if tty devices should be kept open on a zero-byte read; otherwise returns false.
  479. The default value is true.
  480. Some serial devices return zero bytes when there is no data available,
  481. instead of returning the system error \c EWOULDBLOCK. When keepOpen()
  482. is true, a zero-byte read will be treated the same as \c EWOULDBLOCK.
  483. When keepOpen() is false, a zero-byte read will be interpreted as an
  484. unrecoverable error and the serial port will be closed.
  485. For Bluetooth RFCOMM sockets, keepOpen() should be false.
  486. The keepOpen() state is ignored if the underlying serial device is a
  487. socket connection to a phone simulator.
  488. \sa setKeepOpen()
  489. */
  490. bool QSerialPort::keepOpen() const
  491. {
  492. return d->keepOpen;
  493. }
  494. /*!
  495. Sets the keep open flag to \a value. The default value is true.
  496. Some serial devices return zero bytes when there is no data available,
  497. instead of returning the system error \c EWOULDBLOCK. When \a value
  498. is true, a zero-byte read will be treated the same as \c EWOULDBLOCK.
  499. When \a value is false, a zero-byte read will be interpreted as an
  500. unrecoverable error and the serial port will be closed.
  501. For Bluetooth RFCOMM sockets, \a value should be false.
  502. The state of \a value is ignored if the underlying serial device is a
  503. socket connection to a phone simulator.
  504. \sa keepOpen()
  505. */
  506. void QSerialPort::setKeepOpen( bool value )
  507. {
  508. d->keepOpen = value;
  509. }
  510. /*!
  511. \reimp
  512. */
  513. bool QSerialPort::dtr() const
  514. {
  515. return d->dtr;
  516. }
  517. /*!
  518. \reimp
  519. */
  520. void QSerialPort::setDtr( bool value )
  521. {
  522. #ifdef USE_TERMIOS
  523. if ( d->fd != -1 && d->isTty ) {
  524. int status = TIOCM_DTR;
  525. if ( value )
  526. ::ioctl( d->fd, TIOCMBIS, &status );
  527. else
  528. ::ioctl( d->fd, TIOCMBIC, &status );
  529. d->dtr = value;
  530. }
  531. #endif
  532. }
  533. /*!
  534. \reimp
  535. */
  536. bool QSerialPort::dsr() const
  537. {
  538. #ifdef USE_TERMIOS
  539. if ( d->fd != -1 && d->isTty ) {
  540. int status = 0;
  541. ::ioctl( d->fd, TIOCMGET, &status );
  542. return ( ( status & TIOCM_DSR ) != 0 );
  543. }
  544. #endif
  545. return true;
  546. }
  547. /*!
  548. \reimp
  549. */
  550. bool QSerialPort::carrier() const
  551. {
  552. #ifdef USE_TERMIOS
  553. if ( d->fd != -1 && d->isTty ) {
  554. int status = 0;
  555. ::ioctl( d->fd, TIOCMGET, &status );
  556. return ( ( status & TIOCM_CAR ) != 0 );
  557. }
  558. #endif
  559. return true;
  560. }
  561. /*!
  562. \reimp
  563. */
  564. bool QSerialPort::rts() const
  565. {
  566. return d->rts;
  567. }
  568. /*!
  569. \reimp
  570. */
  571. void QSerialPort::setRts( bool value )
  572. {
  573. #ifdef USE_TERMIOS
  574. if ( d->fd != -1 && d->isTty ) {
  575. int status = TIOCM_RTS;
  576. if ( value )
  577. ::ioctl( d->fd, TIOCMBIS, &status );
  578. else
  579. ::ioctl( d->fd, TIOCMBIC, &status );
  580. d->rts = value;
  581. }
  582. #endif
  583. }
  584. /*!
  585. \reimp
  586. */
  587. bool QSerialPort::cts() const
  588. {
  589. #ifdef USE_TERMIOS
  590. if ( d->fd != -1 && d->isTty ) {
  591. int status = 0;
  592. ::ioctl( d->fd, TIOCMGET, &status );
  593. return ( ( status & TIOCM_CTS ) != 0 );
  594. }
  595. #endif
  596. return true;
  597. }
  598. /*!
  599. \reimp
  600. */
  601. void QSerialPort::discard()
  602. {
  603. #ifdef USE_TERMIOS
  604. if ( d->fd != -1 && d->isTty ) {
  605. ::tcflush( d->fd, TCIOFLUSH );
  606. }
  607. #endif
  608. }
  609. /*!
  610. \reimp
  611. */
  612. bool QSerialPort::isValid() const
  613. {
  614. #ifdef USE_POSIX_SYSCALLS
  615. return ( d->fd != -1 );
  616. #else
  617. return QSerialIODevice::isValid();
  618. #endif
  619. }
  620. /*!
  621. \reimp
  622. This class overrides QSerialIODevice::run() to run pppd directly on the
  623. underlying device name so that it isn't necessary to create a pseudo-tty.
  624. This is generally more efficient for running pppd.
  625. */
  626. QProcess *QSerialPort::run( const QStringList& arguments,
  627. bool addPPPdOptions )
  628. {
  629. if ( addPPPdOptions && d->isTty ) {
  630. // Make sure we aren't using the device before handing it off to pppd.
  631. if ( isOpen() )
  632. close();
  633. // Build a new argument list for pppd, with the device name in place.
  634. QStringList newargs;
  635. newargs << d->device;
  636. newargs << QString::number( d->rate );
  637. for ( int index = 1; index < arguments.size(); ++index )
  638. newargs << arguments[index];
  639. // Run the process. When it exits, open() will be called again.
  640. QProcess *process = new QProcess();
  641. process->setReadChannelMode( QProcess::ForwardedChannels );
  642. connect( process, SIGNAL(stateChanged(QProcess::ProcessState)),
  643. this, SLOT(pppdStateChanged(QProcess::ProcessState)) );
  644. connect( process, SIGNAL(destroyed()), this, SLOT(pppdDestroyed()) );
  645. process->start( arguments[0], newargs );
  646. return process;
  647. } else {
  648. return QSerialIODevice::run( arguments, addPPPdOptions );
  649. }
  650. }
  651. void QSerialPort::statusTimeout()
  652. {
  653. #ifdef USE_TERMIOS
  654. if ( d->fd != -1 && d->isTty ) {
  655. int old_status = d->status;
  656. int status = 0;
  657. ::ioctl( d->fd, TIOCMGET, &status );
  658. d->status = status;
  659. if ( ( ( old_status ^ status ) & TIOCM_DSR ) != 0 )
  660. emit dsrChanged( ( status & TIOCM_DSR ) != 0 );
  661. if ( ( ( old_status ^ status ) & TIOCM_CAR ) != 0 )
  662. emit carrierChanged( ( status & TIOCM_CAR ) != 0 );
  663. }
  664. #endif
  665. }
  666. void QSerialPort::pppdStateChanged( QProcess::ProcessState state )
  667. {
  668. if ( state == QProcess::NotRunning && !isOpen() ) {
  669. // The process has exited, so re-open the device for our own use.
  670. open( QIODevice::ReadWrite );
  671. }
  672. }
  673. void QSerialPort::pppdDestroyed()
  674. {
  675. if ( !isOpen() ) {
  676. // The process has been killed, so re-open the device for our own use.
  677. open( QIODevice::ReadWrite );
  678. }
  679. }
  680. /*!
  681. Create and open a serial device from a \a name of the form \c{device:rate}.
  682. Returns NULL if the device could not be opened. The \a defaultRate
  683. parameter indicates the default rate to use if \c{:rate} was not included
  684. in the device name. If \a flowControl is true, then CTS/RTS flow
  685. control should be enabled on the device.
  686. The \a name parameter can have the special form \c{sim:hostname},
  687. where \c hostname is the name of a host running a phone simulator daemon
  688. (usually \c localhost). The phone simulator mode is intended for
  689. debugging purposes only.
  690. */
  691. QSerialPort *QSerialPort::create( const QString& name, int defaultRate,
  692. bool flowControl )
  693. {
  694. int rate = defaultRate;
  695. QString dev = name;
  696. if ( dev.length() > 0 && dev[0] == '/' ) {
  697. int index = dev.indexOf(QChar(':'));
  698. if ( index != -1 ) {
  699. rate = dev.mid( index + 1 ).toInt();
  700. dev = dev.left( index );
  701. }
  702. }
  703. qDebug() << "opening serial device " << dev << " at " << rate;
  704. QSerialPort *device = new QSerialPort( dev, rate );
  705. device->setFlowControl( flowControl );
  706. if ( !device->open( ReadWrite ) ) {
  707. qWarning() << "Failed opening " << dev;
  708. delete device;
  709. return 0;
  710. } else {
  711. qDebug() << "Opened " << dev;
  712. return device;
  713. }
  714. }