1 /* Copyright 2012 William Woodall and John Harrison
2 *
3 * Additional Contributors: Christopher Baker @bakercp
4 */
5
6 #if !defined(_WIN32)
7 #include "stdafx.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <sstream>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include <paths.h>
17 #include <sysexits.h>
18 #include <termios.h>
19 #include <sys/param.h>
20 #include <pthread.h>
21
22 #if defined(__linux__)
23 # include <linux/serial.h>
24 #endif
25
26 #include <sys/select.h>
27 #include <time.h>
28 #ifdef __MACH__
29 #include <AvailabilityMacros.h>
30 #include <mach/clock.h>
31 #include <mach/mach.h>
32 #endif
33
34 #include "unix.h"
35
36 #ifndef TIOCINQ
37 #ifdef FIONREAD
38 #define TIOCINQ FIONREAD
39 #else
40 #define TIOCINQ 0x541B
41 #endif
42 #endif
43
44 #if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
45 #include <IOKit/serial/ioss.h>
46 #endif
47
48 using std::string;
49 using std::stringstream;
50 using std::invalid_argument;
51 using serial::MillisecondTimer;
52 using serial::Serial;
53 using serial::SerialException;
54 using serial::PortNotOpenedException;
55 using serial::IOException;
56
57
MillisecondTimer(const uint32_t millis)58 MillisecondTimer::MillisecondTimer (const uint32_t millis)
59 : expiry(timespec_now())
60 {
61 int64_t tv_nsec = expiry.tv_nsec + (millis * 1e6);
62 if (tv_nsec >= 1e9) {
63 int64_t sec_diff = tv_nsec / static_cast<int> (1e9);
64 expiry.tv_nsec = tv_nsec - static_cast<int> (1e9 * sec_diff);
65 expiry.tv_sec += sec_diff;
66 } else {
67 expiry.tv_nsec = tv_nsec;
68 }
69 }
70
71 int64_t
remaining()72 MillisecondTimer::remaining ()
73 {
74 timespec now(timespec_now());
75 int64_t millis = (expiry.tv_sec - now.tv_sec) * 1e3;
76 millis += (expiry.tv_nsec - now.tv_nsec) / 1e6;
77 return millis;
78 }
79
80 timespec
timespec_now()81 MillisecondTimer::timespec_now ()
82 {
83 timespec time;
84 # ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
85 clock_serv_t cclock;
86 mach_timespec_t mts;
87 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
88 clock_get_time(cclock, &mts);
89 mach_port_deallocate(mach_task_self(), cclock);
90 time.tv_sec = mts.tv_sec;
91 time.tv_nsec = mts.tv_nsec;
92 # else
93 clock_gettime(CLOCK_REALTIME, &time);
94 # endif
95 return time;
96 }
97
98 timespec
timespec_from_ms(const uint32_t millis)99 timespec_from_ms (const uint32_t millis)
100 {
101 timespec time;
102 time.tv_sec = millis / 1e3;
103 time.tv_nsec = (millis - (time.tv_sec * 1e3)) * 1e6;
104 return time;
105 }
106
SerialImpl(const string & port,unsigned long baudrate,bytesize_t bytesize,parity_t parity,stopbits_t stopbits,flowcontrol_t flowcontrol)107 Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
108 bytesize_t bytesize,
109 parity_t parity, stopbits_t stopbits,
110 flowcontrol_t flowcontrol)
111 : port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (false), rtscts_ (false),
112 baudrate_ (baudrate), parity_ (parity),
113 bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
114 {
115 pthread_mutex_init(&this->read_mutex, NULL);
116 pthread_mutex_init(&this->write_mutex, NULL);
117 if (port_.empty () == false)
118 open ();
119 }
120
~SerialImpl()121 Serial::SerialImpl::~SerialImpl ()
122 {
123 close();
124 pthread_mutex_destroy(&this->read_mutex);
125 pthread_mutex_destroy(&this->write_mutex);
126 }
127
128 void
open()129 Serial::SerialImpl::open ()
130 {
131 if (port_.empty ()) {
132 throw invalid_argument ("Empty port is invalid.");
133 }
134 if (is_open_ == true) {
135 throw SerialException ("Serial port already open.");
136 }
137
138 fd_ = ::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
139
140 if (fd_ == -1) {
141 switch (errno) {
142 case EINTR:
143 // Recurse because this is a recoverable error.
144 open ();
145 return;
146 case ENFILE:
147 case EMFILE:
148 THROW (IOException, "Too many file handles open.");
149 default:
150 THROW (IOException, errno);
151 }
152 }
153
154 reconfigurePort();
155 is_open_ = true;
156 }
157
158 void
reconfigurePort()159 Serial::SerialImpl::reconfigurePort ()
160 {
161 if (fd_ == -1) {
162 // Can only operate on a valid file descriptor
163 THROW (IOException, "Invalid file descriptor, is the serial port open?");
164 }
165
166 struct termios options; // The options for the file descriptor
167
168 if (tcgetattr(fd_, &options) == -1) {
169 THROW (IOException, "::tcgetattr");
170 }
171
172 // set up raw mode / no echo / binary
173 options.c_cflag |= (tcflag_t) (CLOCAL | CREAD);
174 options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL |
175 ISIG | IEXTEN); //|ECHOPRT
176
177 options.c_oflag &= (tcflag_t) ~(OPOST);
178 options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
179 #ifdef IUCLC
180 options.c_iflag &= (tcflag_t) ~IUCLC;
181 #endif
182 #ifdef PARMRK
183 options.c_iflag &= (tcflag_t) ~PARMRK;
184 #endif
185
186 // setup baud rate
187 bool custom_baud = false;
188 speed_t baud;
189 switch (baudrate_) {
190 #ifdef B0
191 case 0: baud = B0; break;
192 #endif
193 #ifdef B50
194 case 50: baud = B50; break;
195 #endif
196 #ifdef B75
197 case 75: baud = B75; break;
198 #endif
199 #ifdef B110
200 case 110: baud = B110; break;
201 #endif
202 #ifdef B134
203 case 134: baud = B134; break;
204 #endif
205 #ifdef B150
206 case 150: baud = B150; break;
207 #endif
208 #ifdef B200
209 case 200: baud = B200; break;
210 #endif
211 #ifdef B300
212 case 300: baud = B300; break;
213 #endif
214 #ifdef B600
215 case 600: baud = B600; break;
216 #endif
217 #ifdef B1200
218 case 1200: baud = B1200; break;
219 #endif
220 #ifdef B1800
221 case 1800: baud = B1800; break;
222 #endif
223 #ifdef B2400
224 case 2400: baud = B2400; break;
225 #endif
226 #ifdef B4800
227 case 4800: baud = B4800; break;
228 #endif
229 #ifdef B7200
230 case 7200: baud = B7200; break;
231 #endif
232 #ifdef B9600
233 case 9600: baud = B9600; break;
234 #endif
235 #ifdef B14400
236 case 14400: baud = B14400; break;
237 #endif
238 #ifdef B19200
239 case 19200: baud = B19200; break;
240 #endif
241 #ifdef B28800
242 case 28800: baud = B28800; break;
243 #endif
244 #ifdef B57600
245 case 57600: baud = B57600; break;
246 #endif
247 #ifdef B76800
248 case 76800: baud = B76800; break;
249 #endif
250 #ifdef B38400
251 case 38400: baud = B38400; break;
252 #endif
253 #ifdef B115200
254 case 115200: baud = B115200; break;
255 #endif
256 #ifdef B128000
257 case 128000: baud = B128000; break;
258 #endif
259 #ifdef B153600
260 case 153600: baud = B153600; break;
261 #endif
262 #ifdef B230400
263 case 230400: baud = B230400; break;
264 #endif
265 #ifdef B256000
266 case 256000: baud = B256000; break;
267 #endif
268 #ifdef B460800
269 case 460800: baud = B460800; break;
270 #endif
271 #ifdef B576000
272 case 576000: baud = B576000; break;
273 #endif
274 #ifdef B921600
275 case 921600: baud = B921600; break;
276 #endif
277 #ifdef B1000000
278 case 1000000: baud = B1000000; break;
279 #endif
280 #ifdef B1152000
281 case 1152000: baud = B1152000; break;
282 #endif
283 #ifdef B1500000
284 case 1500000: baud = B1500000; break;
285 #endif
286 #ifdef B2000000
287 case 2000000: baud = B2000000; break;
288 #endif
289 #ifdef B2500000
290 case 2500000: baud = B2500000; break;
291 #endif
292 #ifdef B3000000
293 case 3000000: baud = B3000000; break;
294 #endif
295 #ifdef B3500000
296 case 3500000: baud = B3500000; break;
297 #endif
298 #ifdef B4000000
299 case 4000000: baud = B4000000; break;
300 #endif
301 default:
302 custom_baud = true;
303 // OS X support
304 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
305 // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates
306 // other than those specified by POSIX. The driver for the underlying serial hardware
307 // ultimately determines which baud rates can be used. This ioctl sets both the input
308 // and output speed.
309 speed_t new_baud = static_cast<speed_t> (baudrate_);
310 if (-1 == ioctl (fd_, IOSSIOSPEED, &new_baud, 1)) {
311 THROW (IOException, errno);
312 }
313 // Linux Support
314 #elif defined(__linux__) && defined (TIOCSSERIAL)
315 struct serial_struct ser;
316
317 if (-1 == ioctl (fd_, TIOCGSERIAL, &ser)) {
318 THROW (IOException, errno);
319 }
320
321 // set custom divisor
322 ser.custom_divisor = ser.baud_base / static_cast<int> (baudrate_);
323 // update flags
324 ser.flags &= ~ASYNC_SPD_MASK;
325 ser.flags |= ASYNC_SPD_CUST;
326
327 if (-1 == ioctl (fd_, TIOCSSERIAL, &ser)) {
328 THROW (IOException, errno);
329 }
330 #else
331 throw invalid_argument ("OS does not currently support custom bauds");
332 #endif
333 }
334 if (custom_baud == false) {
335 #ifdef _BSD_SOURCE
336 ::cfsetspeed(&options, baud);
337 #else
338 ::cfsetispeed(&options, baud);
339 ::cfsetospeed(&options, baud);
340 #endif
341 }
342
343 // setup char len
344 options.c_cflag &= (tcflag_t) ~CSIZE;
345 if (bytesize_ == eightbits)
346 options.c_cflag |= CS8;
347 else if (bytesize_ == sevenbits)
348 options.c_cflag |= CS7;
349 else if (bytesize_ == sixbits)
350 options.c_cflag |= CS6;
351 else if (bytesize_ == fivebits)
352 options.c_cflag |= CS5;
353 else
354 throw invalid_argument ("invalid char len");
355 // setup stopbits
356 if (stopbits_ == stopbits_one)
357 options.c_cflag &= (tcflag_t) ~(CSTOPB);
358 else if (stopbits_ == stopbits_one_point_five)
359 // ONE POINT FIVE same as TWO.. there is no POSIX support for 1.5
360 options.c_cflag |= (CSTOPB);
361 else if (stopbits_ == stopbits_two)
362 options.c_cflag |= (CSTOPB);
363 else
364 throw invalid_argument ("invalid stop bit");
365 // setup parity
366 options.c_iflag &= (tcflag_t) ~(INPCK | ISTRIP);
367 if (parity_ == parity_none) {
368 options.c_cflag &= (tcflag_t) ~(PARENB | PARODD);
369 } else if (parity_ == parity_even) {
370 options.c_cflag &= (tcflag_t) ~(PARODD);
371 options.c_cflag |= (PARENB);
372 } else if (parity_ == parity_odd) {
373 options.c_cflag |= (PARENB | PARODD);
374 }
375 #ifdef CMSPAR
376 else if (parity_ == parity_mark) {
377 options.c_cflag |= (PARENB | CMSPAR | PARODD);
378 }
379 else if (parity_ == parity_space) {
380 options.c_cflag |= (PARENB | CMSPAR);
381 options.c_cflag &= (tcflag_t) ~(PARODD);
382 }
383 #else
384 // CMSPAR is not defined on OSX. So do not support mark or space parity.
385 else if (parity_ == parity_mark || parity_ == parity_space) {
386 throw invalid_argument ("OS does not support mark or space parity");
387 }
388 #endif // ifdef CMSPAR
389 else {
390 throw invalid_argument ("invalid parity");
391 }
392 // setup flow control
393 if (flowcontrol_ == flowcontrol_none) {
394 xonxoff_ = false;
395 rtscts_ = false;
396 }
397 if (flowcontrol_ == flowcontrol_software) {
398 xonxoff_ = true;
399 rtscts_ = false;
400 }
401 if (flowcontrol_ == flowcontrol_hardware) {
402 xonxoff_ = false;
403 rtscts_ = true;
404 }
405 // xonxoff
406 #ifdef IXANY
407 if (xonxoff_)
408 options.c_iflag |= (IXON | IXOFF); //|IXANY)
409 else
410 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | IXANY);
411 #else
412 if (xonxoff_)
413 options.c_iflag |= (IXON | IXOFF);
414 else
415 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF);
416 #endif
417 // rtscts
418 #ifdef CRTSCTS
419 if (rtscts_)
420 options.c_cflag |= (CRTSCTS);
421 else
422 options.c_cflag &= (unsigned long) ~(CRTSCTS);
423 #elif defined CNEW_RTSCTS
424 if (rtscts_)
425 options.c_cflag |= (CNEW_RTSCTS);
426 else
427 options.c_cflag &= (unsigned long) ~(CNEW_RTSCTS);
428 #else
429 #error "OS Support seems wrong."
430 #endif
431
432 // http://www.unixwiz.net/techtips/termios-vmin-vtime.html
433 // this basically sets the read call up to be a polling read,
434 // but we are using select to ensure there is data available
435 // to read before each call, so we should never needlessly poll
436 options.c_cc[VMIN] = 0;
437 options.c_cc[VTIME] = 0;
438
439 // activate settings
440 ::tcsetattr (fd_, TCSANOW, &options);
441
442 // Update byte_time_ based on the new settings.
443 uint32_t bit_time_ns = 1e9 / baudrate_;
444 byte_time_ns_ = bit_time_ns * (1 + bytesize_ + parity_ + stopbits_);
445
446 // Compensate for the stopbits_one_point_five enum being equal to int 3,
447 // and not 1.5.
448 if (stopbits_ == stopbits_one_point_five) {
449 byte_time_ns_ += ((1.5 - stopbits_one_point_five) * bit_time_ns);
450 }
451 }
452
453 void
close()454 Serial::SerialImpl::close ()
455 {
456 if (is_open_ == true) {
457 if (fd_ != -1) {
458 int ret;
459 ret = ::close (fd_);
460 if (ret == 0) {
461 fd_ = -1;
462 } else {
463 THROW (IOException, errno);
464 }
465 }
466 is_open_ = false;
467 }
468 }
469
470 bool
isOpen() const471 Serial::SerialImpl::isOpen () const
472 {
473 return is_open_;
474 }
475
476 size_t
available()477 Serial::SerialImpl::available ()
478 {
479 if (!is_open_) {
480 return 0;
481 }
482 int count = 0;
483 if (-1 == ioctl (fd_, TIOCINQ, &count)) {
484 THROW (IOException, errno);
485 } else {
486 return static_cast<size_t> (count);
487 }
488 }
489
490 bool
waitReadable(uint32_t timeout)491 Serial::SerialImpl::waitReadable (uint32_t timeout)
492 {
493 // Setup a select call to block for serial data or a timeout
494 fd_set readfds;
495 FD_ZERO (&readfds);
496 FD_SET (fd_, &readfds);
497 timespec timeout_ts (timespec_from_ms (timeout));
498 int r = pselect (fd_ + 1, &readfds, NULL, NULL, &timeout_ts, NULL);
499
500 if (r < 0) {
501 // Select was interrupted
502 if (errno == EINTR) {
503 return false;
504 }
505 // Otherwise there was some error
506 THROW (IOException, errno);
507 }
508 // Timeout occurred
509 if (r == 0) {
510 return false;
511 }
512 // This shouldn't happen, if r > 0 our fd has to be in the list!
513 if (!FD_ISSET (fd_, &readfds)) {
514 THROW (IOException, "select reports ready to read, but our fd isn't"
515 " in the list, this shouldn't happen!");
516 }
517 // Data available to read.
518 return true;
519 }
520
521 void
waitByteTimes(size_t count)522 Serial::SerialImpl::waitByteTimes (size_t count)
523 {
524 timespec wait_time = { 0, static_cast<long>(byte_time_ns_ * count)};
525 pselect (0, NULL, NULL, NULL, &wait_time, NULL);
526 }
527
528 size_t
read(uint8_t * buf,size_t size)529 Serial::SerialImpl::read (uint8_t *buf, size_t size)
530 {
531 // If the port is not open, throw
532 if (!is_open_) {
533 throw PortNotOpenedException ("Serial::read");
534 }
535 size_t bytes_read = 0;
536
537 // Calculate total timeout in milliseconds t_c + (t_m * N)
538 long total_timeout_ms = timeout_.read_timeout_constant;
539 total_timeout_ms += timeout_.read_timeout_multiplier * static_cast<long> (size);
540 MillisecondTimer total_timeout(total_timeout_ms);
541
542 // Pre-fill buffer with available bytes
543 {
544 ssize_t bytes_read_now = ::read (fd_, buf, size);
545 if (bytes_read_now > 0) {
546 bytes_read = bytes_read_now;
547 }
548 }
549
550 while (bytes_read < size) {
551 int64_t timeout_remaining_ms = total_timeout.remaining();
552 if (timeout_remaining_ms <= 0) {
553 // Timed out
554 break;
555 }
556 // Timeout for the next select is whichever is less of the remaining
557 // total read timeout and the inter-byte timeout.
558 uint32_t timeout = std::min(static_cast<uint32_t> (timeout_remaining_ms),
559 timeout_.inter_byte_timeout);
560 // Wait for the device to be readable, and then attempt to read.
561 if (waitReadable(timeout)) {
562 // If it's a fixed-length multi-byte read, insert a wait here so that
563 // we can attempt to grab the whole thing in a single IO call. Skip
564 // this wait if a non-max inter_byte_timeout is specified.
565 if (size > 1 && timeout_.inter_byte_timeout == Timeout::max()) {
566 size_t bytes_available = available();
567 if (bytes_available + bytes_read < size) {
568 waitByteTimes(size - (bytes_available + bytes_read));
569 }
570 }
571 // This should be non-blocking returning only what is available now
572 // Then returning so that select can block again.
573 ssize_t bytes_read_now =
574 ::read (fd_, buf + bytes_read, size - bytes_read);
575 // read should always return some data as select reported it was
576 // ready to read when we get to this point.
577 if (bytes_read_now < 1) {
578 // Disconnected devices, at least on Linux, show the
579 // behavior that they are always ready to read immediately
580 // but reading returns nothing.
581 throw SerialException ("device reports readiness to read but "
582 "returned no data (device disconnected?)");
583 }
584 // Update bytes_read
585 bytes_read += static_cast<size_t> (bytes_read_now);
586 // If bytes_read == size then we have read everything we need
587 if (bytes_read == size) {
588 break;
589 }
590 // If bytes_read < size then we have more to read
591 if (bytes_read < size) {
592 continue;
593 }
594 // If bytes_read > size then we have over read, which shouldn't happen
595 if (bytes_read > size) {
596 throw SerialException ("read over read, too many bytes where "
597 "read, this shouldn't happen, might be "
598 "a logical error!");
599 }
600 }
601 }
602 return bytes_read;
603 }
604
605 size_t
write(const uint8_t * data,size_t length)606 Serial::SerialImpl::write (const uint8_t *data, size_t length)
607 {
608 if (is_open_ == false) {
609 throw PortNotOpenedException ("Serial::write");
610 }
611 fd_set writefds;
612 size_t bytes_written = 0;
613
614 // Calculate total timeout in milliseconds t_c + (t_m * N)
615 long total_timeout_ms = timeout_.write_timeout_constant;
616 total_timeout_ms += timeout_.write_timeout_multiplier * static_cast<long> (length);
617 MillisecondTimer total_timeout(total_timeout_ms);
618
619 while (bytes_written < length) {
620 int64_t timeout_remaining_ms = total_timeout.remaining();
621 if (timeout_remaining_ms <= 0) {
622 // Timed out
623 break;
624 }
625 timespec timeout(timespec_from_ms(timeout_remaining_ms));
626
627 FD_ZERO (&writefds);
628 FD_SET (fd_, &writefds);
629
630 // Do the select
631 int r = pselect (fd_ + 1, NULL, &writefds, NULL, &timeout, NULL);
632
633 // Figure out what happened by looking at select's response 'r'
634 /** Error **/
635 if (r < 0) {
636 // Select was interrupted, try again
637 if (errno == EINTR) {
638 continue;
639 }
640 // Otherwise there was some error
641 THROW (IOException, errno);
642 }
643 /** Timeout **/
644 if (r == 0) {
645 break;
646 }
647 /** Port ready to write **/
648 if (r > 0) {
649 // Make sure our file descriptor is in the ready to write list
650 if (FD_ISSET (fd_, &writefds)) {
651 // This will write some
652 ssize_t bytes_written_now =
653 ::write (fd_, data + bytes_written, length - bytes_written);
654 // write should always return some data as select reported it was
655 // ready to write when we get to this point.
656 if (bytes_written_now < 1) {
657 // Disconnected devices, at least on Linux, show the
658 // behavior that they are always ready to write immediately
659 // but writing returns nothing.
660 throw SerialException ("device reports readiness to write but "
661 "returned no data (device disconnected?)");
662 }
663 // Update bytes_written
664 bytes_written += static_cast<size_t> (bytes_written_now);
665 // If bytes_written == size then we have written everything we need to
666 if (bytes_written == length) {
667 break;
668 }
669 // If bytes_written < size then we have more to write
670 if (bytes_written < length) {
671 continue;
672 }
673 // If bytes_written > size then we have over written, which shouldn't happen
674 if (bytes_written > length) {
675 throw SerialException ("write over wrote, too many bytes where "
676 "written, this shouldn't happen, might be "
677 "a logical error!");
678 }
679 }
680 // This shouldn't happen, if r > 0 our fd has to be in the list!
681 THROW (IOException, "select reports ready to write, but our fd isn't"
682 " in the list, this shouldn't happen!");
683 }
684 }
685 return bytes_written;
686 }
687
688 void
setPort(const string & port)689 Serial::SerialImpl::setPort (const string &port)
690 {
691 port_ = port;
692 }
693
694 string
getPort() const695 Serial::SerialImpl::getPort () const
696 {
697 return port_;
698 }
699
700 void
setTimeout(serial::Timeout & timeout)701 Serial::SerialImpl::setTimeout (serial::Timeout &timeout)
702 {
703 timeout_ = timeout;
704 }
705
706 serial::Timeout
getTimeout() const707 Serial::SerialImpl::getTimeout () const
708 {
709 return timeout_;
710 }
711
712 void
setBaudrate(unsigned long baudrate)713 Serial::SerialImpl::setBaudrate (unsigned long baudrate)
714 {
715 baudrate_ = baudrate;
716 if (is_open_)
717 reconfigurePort ();
718 }
719
720 unsigned long
getBaudrate() const721 Serial::SerialImpl::getBaudrate () const
722 {
723 return baudrate_;
724 }
725
726 void
setBytesize(serial::bytesize_t bytesize)727 Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
728 {
729 bytesize_ = bytesize;
730 if (is_open_)
731 reconfigurePort ();
732 }
733
734 serial::bytesize_t
getBytesize() const735 Serial::SerialImpl::getBytesize () const
736 {
737 return bytesize_;
738 }
739
740 void
setParity(serial::parity_t parity)741 Serial::SerialImpl::setParity (serial::parity_t parity)
742 {
743 parity_ = parity;
744 if (is_open_)
745 reconfigurePort ();
746 }
747
748 serial::parity_t
getParity() const749 Serial::SerialImpl::getParity () const
750 {
751 return parity_;
752 }
753
754 void
setStopbits(serial::stopbits_t stopbits)755 Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
756 {
757 stopbits_ = stopbits;
758 if (is_open_)
759 reconfigurePort ();
760 }
761
762 serial::stopbits_t
getStopbits() const763 Serial::SerialImpl::getStopbits () const
764 {
765 return stopbits_;
766 }
767
768 void
setFlowcontrol(serial::flowcontrol_t flowcontrol)769 Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
770 {
771 flowcontrol_ = flowcontrol;
772 if (is_open_)
773 reconfigurePort ();
774 }
775
776 serial::flowcontrol_t
getFlowcontrol() const777 Serial::SerialImpl::getFlowcontrol () const
778 {
779 return flowcontrol_;
780 }
781
782 void
flush()783 Serial::SerialImpl::flush ()
784 {
785 if (is_open_ == false) {
786 throw PortNotOpenedException ("Serial::flush");
787 }
788 tcdrain (fd_);
789 }
790
791 void
flushInput()792 Serial::SerialImpl::flushInput ()
793 {
794 if (is_open_ == false) {
795 throw PortNotOpenedException ("Serial::flushInput");
796 }
797 tcflush (fd_, TCIFLUSH);
798 }
799
800 void
flushOutput()801 Serial::SerialImpl::flushOutput ()
802 {
803 if (is_open_ == false) {
804 throw PortNotOpenedException ("Serial::flushOutput");
805 }
806 tcflush (fd_, TCOFLUSH);
807 }
808
809 void
sendBreak(int duration)810 Serial::SerialImpl::sendBreak (int duration)
811 {
812 if (is_open_ == false) {
813 throw PortNotOpenedException ("Serial::sendBreak");
814 }
815 tcsendbreak (fd_, static_cast<int> (duration / 4));
816 }
817
818 void
setBreak(bool level)819 Serial::SerialImpl::setBreak (bool level)
820 {
821 if (is_open_ == false) {
822 throw PortNotOpenedException ("Serial::setBreak");
823 }
824
825 if (level) {
826 if (-1 == ioctl (fd_, TIOCSBRK))
827 {
828 stringstream ss;
829 ss << "setBreak failed on a call to ioctl(TIOCSBRK): " << errno << " " << strerror(errno);
830 throw(SerialException(ss.str().c_str()));
831 }
832 } else {
833 if (-1 == ioctl (fd_, TIOCCBRK))
834 {
835 stringstream ss;
836 ss << "setBreak failed on a call to ioctl(TIOCCBRK): " << errno << " " << strerror(errno);
837 throw(SerialException(ss.str().c_str()));
838 }
839 }
840 }
841
842 void
setRTS(bool level)843 Serial::SerialImpl::setRTS (bool level)
844 {
845 if (is_open_ == false) {
846 throw PortNotOpenedException ("Serial::setRTS");
847 }
848
849 int command = TIOCM_RTS;
850
851 if (level) {
852 if (-1 == ioctl (fd_, TIOCMBIS, &command))
853 {
854 stringstream ss;
855 ss << "setRTS failed on a call to ioctl(TIOCMBIS): " << errno << " " << strerror(errno);
856 throw(SerialException(ss.str().c_str()));
857 }
858 } else {
859 if (-1 == ioctl (fd_, TIOCMBIC, &command))
860 {
861 stringstream ss;
862 ss << "setRTS failed on a call to ioctl(TIOCMBIC): " << errno << " " << strerror(errno);
863 throw(SerialException(ss.str().c_str()));
864 }
865 }
866 }
867
868 void
setDTR(bool level)869 Serial::SerialImpl::setDTR (bool level)
870 {
871 if (is_open_ == false) {
872 throw PortNotOpenedException ("Serial::setDTR");
873 }
874
875 int command = TIOCM_DTR;
876
877 if (level) {
878 if (-1 == ioctl (fd_, TIOCMBIS, &command))
879 {
880 stringstream ss;
881 ss << "setDTR failed on a call to ioctl(TIOCMBIS): " << errno << " " << strerror(errno);
882 throw(SerialException(ss.str().c_str()));
883 }
884 } else {
885 if (-1 == ioctl (fd_, TIOCMBIC, &command))
886 {
887 stringstream ss;
888 ss << "setDTR failed on a call to ioctl(TIOCMBIC): " << errno << " " << strerror(errno);
889 throw(SerialException(ss.str().c_str()));
890 }
891 }
892 }
893
894 bool
waitForChange()895 Serial::SerialImpl::waitForChange ()
896 {
897 #ifndef TIOCMIWAIT
898
899 while (is_open_ == true) {
900
901 int status;
902
903 if (-1 == ioctl (fd_, TIOCMGET, &status))
904 {
905 stringstream ss;
906 ss << "waitForChange failed on a call to ioctl(TIOCMGET): " << errno << " " << strerror(errno);
907 throw(SerialException(ss.str().c_str()));
908 }
909 else
910 {
911 if (0 != (status & TIOCM_CTS)
912 || 0 != (status & TIOCM_DSR)
913 || 0 != (status & TIOCM_RI)
914 || 0 != (status & TIOCM_CD))
915 {
916 return true;
917 }
918 }
919
920 usleep(1000);
921 }
922
923 return false;
924 #else
925 int command = (TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS);
926
927 if (-1 == ioctl (fd_, TIOCMIWAIT, &command)) {
928 stringstream ss;
929 ss << "waitForDSR failed on a call to ioctl(TIOCMIWAIT): "
930 << errno << " " << strerror(errno);
931 throw(SerialException(ss.str().c_str()));
932 }
933 return true;
934 #endif
935 }
936
937 bool
getCTS()938 Serial::SerialImpl::getCTS ()
939 {
940 if (is_open_ == false) {
941 throw PortNotOpenedException ("Serial::getCTS");
942 }
943
944 int status;
945
946 if (-1 == ioctl (fd_, TIOCMGET, &status))
947 {
948 stringstream ss;
949 ss << "getCTS failed on a call to ioctl(TIOCMGET): " << errno << " " << strerror(errno);
950 throw(SerialException(ss.str().c_str()));
951 }
952 else
953 {
954 return 0 != (status & TIOCM_CTS);
955 }
956 }
957
958 bool
getDSR()959 Serial::SerialImpl::getDSR ()
960 {
961 if (is_open_ == false) {
962 throw PortNotOpenedException ("Serial::getDSR");
963 }
964
965 int status;
966
967 if (-1 == ioctl (fd_, TIOCMGET, &status))
968 {
969 stringstream ss;
970 ss << "getDSR failed on a call to ioctl(TIOCMGET): " << errno << " " << strerror(errno);
971 throw(SerialException(ss.str().c_str()));
972 }
973 else
974 {
975 return 0 != (status & TIOCM_DSR);
976 }
977 }
978
979 bool
getRI()980 Serial::SerialImpl::getRI ()
981 {
982 if (is_open_ == false) {
983 throw PortNotOpenedException ("Serial::getRI");
984 }
985
986 int status;
987
988 if (-1 == ioctl (fd_, TIOCMGET, &status))
989 {
990 stringstream ss;
991 ss << "getRI failed on a call to ioctl(TIOCMGET): " << errno << " " << strerror(errno);
992 throw(SerialException(ss.str().c_str()));
993 }
994 else
995 {
996 return 0 != (status & TIOCM_RI);
997 }
998 }
999
1000 bool
getCD()1001 Serial::SerialImpl::getCD ()
1002 {
1003 if (is_open_ == false) {
1004 throw PortNotOpenedException ("Serial::getCD");
1005 }
1006
1007 int status;
1008
1009 if (-1 == ioctl (fd_, TIOCMGET, &status))
1010 {
1011 stringstream ss;
1012 ss << "getCD failed on a call to ioctl(TIOCMGET): " << errno << " " << strerror(errno);
1013 throw(SerialException(ss.str().c_str()));
1014 }
1015 else
1016 {
1017 return 0 != (status & TIOCM_CD);
1018 }
1019 }
1020
1021 void
readLock()1022 Serial::SerialImpl::readLock ()
1023 {
1024 int result = pthread_mutex_lock(&this->read_mutex);
1025 if (result) {
1026 THROW (IOException, result);
1027 }
1028 }
1029
1030 void
readUnlock()1031 Serial::SerialImpl::readUnlock ()
1032 {
1033 int result = pthread_mutex_unlock(&this->read_mutex);
1034 if (result) {
1035 THROW (IOException, result);
1036 }
1037 }
1038
1039 void
writeLock()1040 Serial::SerialImpl::writeLock ()
1041 {
1042 int result = pthread_mutex_lock(&this->write_mutex);
1043 if (result) {
1044 THROW (IOException, result);
1045 }
1046 }
1047
1048 void
writeUnlock()1049 Serial::SerialImpl::writeUnlock ()
1050 {
1051 int result = pthread_mutex_unlock(&this->write_mutex);
1052 if (result) {
1053 THROW (IOException, result);
1054 }
1055 }
1056
1057 #endif // !defined(_WIN32)
1058