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