13 #include <sys/ioctl.h>
14 #include <sys/signal.h>
19 #include <sys/param.h>
22 #if defined(__linux__)
23 # include <linux/serial.h>
26 #include <sys/select.h>
30 #include <AvailabilityMacros.h>
31 #include <mach/clock.h>
32 #include <mach/mach.h>
39 #define TIOCINQ FIONREAD
41 #define TIOCINQ 0x541B
45 #if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3)
46 #include <IOKit/serial/ioss.h>
50 using std::stringstream;
51 using std::invalid_argument;
59 MillisecondTimer::MillisecondTimer (
const uint32_t millis)
60 : expiry(timespec_now())
62 int64_t tv_nsec =
expiry.tv_nsec + (millis * 1e6);
64 int64_t sec_diff = tv_nsec /
static_cast<int> (1e9);
65 expiry.tv_nsec = tv_nsec %
static_cast<int>(1e9);
76 int64_t millis = (
expiry.tv_sec - now.tv_sec) * 1e3;
77 millis += (
expiry.tv_nsec - now.tv_nsec) / 1e6;
85 # ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
88 host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
89 clock_get_time(cclock, &mts);
90 mach_port_deallocate(mach_task_self(), cclock);
91 time.tv_sec = mts.tv_sec;
92 time.tv_nsec = mts.tv_nsec;
94 clock_gettime(CLOCK_MONOTONIC, &time);
103 time.tv_sec = millis / 1e3;
104 time.tv_nsec = (millis - (time.tv_sec * 1e3)) * 1e6;
112 : port_ (port), fd_ (-1), is_open_ (false), xonxoff_ (false), rtscts_ (false),
113 baudrate_ (baudrate), parity_ (parity),
114 bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
118 if (
port_.empty () ==
false)
125 pthread_mutex_destroy(&this->read_mutex);
126 pthread_mutex_destroy(&this->write_mutex);
132 if (port_.empty ()) {
133 throw invalid_argument (
"Empty port is invalid.");
135 if (is_open_ ==
true) {
139 fd_ =
::open (port_.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
167 struct termios options;
169 if (tcgetattr(fd_, &options) == -1) {
174 options.c_cflag |= (tcflag_t) (CLOCAL | CREAD);
175 options.c_lflag &= (tcflag_t) ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL |
178 options.c_oflag &= (tcflag_t) ~(OPOST);
179 options.c_iflag &= (tcflag_t) ~(INLCR | IGNCR | ICRNL | IGNBRK);
181 options.c_iflag &= (tcflag_t) ~IUCLC;
184 options.c_iflag &= (tcflag_t) ~PARMRK;
188 bool custom_baud =
false;
192 case 0: baud = B0;
break;
195 case 50: baud = B50;
break;
198 case 75: baud = B75;
break;
201 case 110: baud = B110;
break;
204 case 134: baud = B134;
break;
207 case 150: baud = B150;
break;
210 case 200: baud = B200;
break;
213 case 300: baud = B300;
break;
216 case 600: baud = B600;
break;
219 case 1200: baud = B1200;
break;
222 case 1800: baud = B1800;
break;
225 case 2400: baud = B2400;
break;
228 case 4800: baud = B4800;
break;
231 case 7200: baud = B7200;
break;
234 case 9600: baud = B9600;
break;
237 case 14400: baud = B14400;
break;
240 case 19200: baud = B19200;
break;
243 case 28800: baud = B28800;
break;
246 case 57600: baud = B57600;
break;
249 case 76800: baud = B76800;
break;
252 case 38400: baud = B38400;
break;
255 case 115200: baud = B115200;
break;
258 case 128000: baud = B128000;
break;
261 case 153600: baud = B153600;
break;
264 case 230400: baud = B230400;
break;
267 case 256000: baud = B256000;
break;
270 case 460800: baud = B460800;
break;
273 case 500000: baud = B500000;
break;
276 case 576000: baud = B576000;
break;
279 case 921600: baud = B921600;
break;
282 case 1000000: baud = B1000000;
break;
285 case 1152000: baud = B1152000;
break;
288 case 1500000: baud = B1500000;
break;
291 case 2000000: baud = B2000000;
break;
294 case 2500000: baud = B2500000;
break;
297 case 3000000: baud = B3000000;
break;
300 case 3500000: baud = B3500000;
break;
303 case 4000000: baud = B4000000;
break;
308 if (custom_baud ==
false) {
310 ::cfsetspeed(&options, baud);
312 ::cfsetispeed(&options, baud);
313 ::cfsetospeed(&options, baud);
318 options.c_cflag &= (tcflag_t) ~CSIZE;
320 options.c_cflag |= CS8;
322 options.c_cflag |= CS7;
324 options.c_cflag |= CS6;
326 options.c_cflag |= CS5;
328 throw invalid_argument (
"invalid char len");
331 options.c_cflag &= (tcflag_t) ~(CSTOPB);
334 options.c_cflag |= (CSTOPB);
336 options.c_cflag |= (CSTOPB);
338 throw invalid_argument (
"invalid stop bit");
340 options.c_iflag &= (tcflag_t) ~(INPCK | ISTRIP);
342 options.c_cflag &= (tcflag_t) ~(PARENB | PARODD);
344 options.c_cflag &= (tcflag_t) ~(PARODD);
345 options.c_cflag |= (PARENB);
347 options.c_cflag |= (PARENB | PARODD);
351 options.c_cflag |= (PARENB | CMSPAR | PARODD);
354 options.c_cflag |= (PARENB | CMSPAR);
355 options.c_cflag &= (tcflag_t) ~(PARODD);
360 throw invalid_argument (
"OS does not support mark or space parity");
362 #endif // ifdef CMSPAR
364 throw invalid_argument (
"invalid parity");
382 options.c_iflag |= (IXON | IXOFF);
384 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF | IXANY);
387 options.c_iflag |= (IXON | IXOFF);
389 options.c_iflag &= (tcflag_t) ~(IXON | IXOFF);
394 options.c_cflag |= (CRTSCTS);
396 options.c_cflag &= (
unsigned long) ~(CRTSCTS);
397 #elif defined CNEW_RTSCTS
399 options.c_cflag |= (CNEW_RTSCTS);
401 options.c_cflag &= (
unsigned long) ~(CNEW_RTSCTS);
403 #error "OS Support seems wrong."
410 options.c_cc[VMIN] = 0;
411 options.c_cc[VTIME] = 0;
414 ::tcsetattr (fd_, TCSANOW, &options);
417 if (custom_baud ==
true) {
419 #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
424 speed_t new_baud =
static_cast<speed_t
> (baudrate_);
426 if (-1 == ioctl (fd_, IOSSIOSPEED, &new_baud, 1)) {
430 #elif defined(__linux__) && defined (TIOCSSERIAL)
431 struct serial_struct ser;
433 if (-1 == ioctl (fd_, TIOCGSERIAL, &ser)) {
438 ser.custom_divisor = ser.baud_base /
static_cast<int> (baudrate_);
440 ser.flags &= ~ASYNC_SPD_MASK;
441 ser.flags |= ASYNC_SPD_CUST;
443 if (-1 == ioctl (fd_, TIOCSSERIAL, &ser)) {
447 throw invalid_argument (
"OS does not currently support custom bauds");
452 uint32_t bit_time_ns = 1e9 / baudrate_;
453 byte_time_ns_ = bit_time_ns * (1 + bytesize_ + parity_ + stopbits_);
465 if (is_open_ ==
true) {
492 if (-1 == ioctl (fd_,
TIOCINQ, &count)) {
495 return static_cast<size_t> (count);
505 FD_SET (fd_, &readfds);
507 int r = pselect (fd_ + 1, &readfds, NULL, NULL, &timeout_ts, NULL);
511 if (errno == EINTR) {
522 if (!FD_ISSET (fd_, &readfds)) {
524 " in the list, this shouldn't happen!");
533 timespec wait_time = { 0,
static_cast<long>(byte_time_ns_ * count)};
534 pselect (0, NULL, NULL, NULL, &wait_time, NULL);
544 size_t bytes_read = 0;
547 long total_timeout_ms = timeout_.read_timeout_constant;
548 total_timeout_ms += timeout_.read_timeout_multiplier *
static_cast<long> (size);
553 ssize_t bytes_read_now =
::read (fd_, buf, size);
554 if (bytes_read_now > 0) {
555 bytes_read = bytes_read_now;
559 while (bytes_read < size) {
560 int64_t timeout_remaining_ms = total_timeout.
remaining();
561 if (timeout_remaining_ms <= 0) {
567 uint32_t
timeout = std::min(
static_cast<uint32_t
> (timeout_remaining_ms),
568 timeout_.inter_byte_timeout);
574 if (size > 1 && timeout_.inter_byte_timeout ==
Timeout::max()) {
576 if (bytes_available + bytes_read < size) {
582 ssize_t bytes_read_now =
583 ::read (fd_, buf + bytes_read, size - bytes_read);
586 if (bytes_read_now < 1) {
591 "returned no data (device disconnected?)");
594 bytes_read +=
static_cast<size_t> (bytes_read_now);
596 if (bytes_read == size) {
600 if (bytes_read < size) {
604 if (bytes_read > size) {
606 "read, this shouldn't happen, might be "
617 if (is_open_ ==
false) {
621 size_t bytes_written = 0;
624 long total_timeout_ms = timeout_.write_timeout_constant;
625 total_timeout_ms += timeout_.write_timeout_multiplier *
static_cast<long> (length);
628 bool first_iteration =
true;
629 while (bytes_written < length) {
630 int64_t timeout_remaining_ms = total_timeout.
remaining();
633 if (!first_iteration && (timeout_remaining_ms <= 0)) {
637 first_iteration =
false;
642 FD_SET (fd_, &writefds);
645 int r = pselect (fd_ + 1, NULL, &writefds, NULL, &
timeout, NULL);
651 if (errno == EINTR) {
664 if (FD_ISSET (fd_, &writefds)) {
666 ssize_t bytes_written_now =
667 ::write (fd_, data + bytes_written, length - bytes_written);
671 if (bytes_written_now == -1 && errno == EINTR) {
677 if (bytes_written_now < 1) {
681 std::stringstream strs;
682 strs <<
"device reports readiness to write but "
683 "returned no data (device disconnected?)";
684 strs <<
" errno=" << errno;
685 strs <<
" bytes_written_now= " << bytes_written_now;
686 strs <<
" bytes_written=" << bytes_written;
687 strs <<
" length=" << length;
691 bytes_written +=
static_cast<size_t> (bytes_written_now);
693 if (bytes_written == length) {
697 if (bytes_written < length) {
701 if (bytes_written > length) {
703 "written, this shouldn't happen, might be "
709 " in the list, this shouldn't happen!");
712 return bytes_written;
742 baudrate_ = baudrate;
756 bytesize_ = bytesize;
784 stopbits_ = stopbits;
798 flowcontrol_ = flowcontrol;
812 if (is_open_ ==
false) {
821 if (is_open_ ==
false) {
824 tcflush (fd_, TCIFLUSH);
830 if (is_open_ ==
false) {
833 tcflush (fd_, TCOFLUSH);
839 if (is_open_ ==
false) {
842 tcsendbreak (fd_,
static_cast<int> (duration / 4));
848 if (is_open_ ==
false) {
853 if (-1 == ioctl (fd_, TIOCSBRK))
856 ss <<
"setBreak failed on a call to ioctl(TIOCSBRK): " << errno <<
" " << strerror(errno);
860 if (-1 == ioctl (fd_, TIOCCBRK))
863 ss <<
"setBreak failed on a call to ioctl(TIOCCBRK): " << errno <<
" " << strerror(errno);
872 if (is_open_ ==
false) {
876 int command = TIOCM_RTS;
879 if (-1 == ioctl (fd_, TIOCMBIS, &command))
882 ss <<
"setRTS failed on a call to ioctl(TIOCMBIS): " << errno <<
" " << strerror(errno);
886 if (-1 == ioctl (fd_, TIOCMBIC, &command))
889 ss <<
"setRTS failed on a call to ioctl(TIOCMBIC): " << errno <<
" " << strerror(errno);
898 if (is_open_ ==
false) {
902 int command = TIOCM_DTR;
905 if (-1 == ioctl (fd_, TIOCMBIS, &command))
908 ss <<
"setDTR failed on a call to ioctl(TIOCMBIS): " << errno <<
" " << strerror(errno);
912 if (-1 == ioctl (fd_, TIOCMBIC, &command))
915 ss <<
"setDTR failed on a call to ioctl(TIOCMBIC): " << errno <<
" " << strerror(errno);
926 while (is_open_ ==
true) {
930 if (-1 == ioctl (fd_, TIOCMGET, &status))
933 ss <<
"waitForChange failed on a call to ioctl(TIOCMGET): " << errno <<
" " << strerror(errno);
938 if (0 != (status & TIOCM_CTS)
939 || 0 != (status & TIOCM_DSR)
940 || 0 != (status & TIOCM_RI)
941 || 0 != (status & TIOCM_CD))
952 int command = (TIOCM_CD|TIOCM_DSR|TIOCM_RI|TIOCM_CTS);
954 if (-1 == ioctl (fd_, TIOCMIWAIT, &command)) {
956 ss <<
"waitForDSR failed on a call to ioctl(TIOCMIWAIT): "
957 << errno <<
" " << strerror(errno);
967 if (is_open_ ==
false) {
973 if (-1 == ioctl (fd_, TIOCMGET, &status))
976 ss <<
"getCTS failed on a call to ioctl(TIOCMGET): " << errno <<
" " << strerror(errno);
981 return 0 != (status & TIOCM_CTS);
988 if (is_open_ ==
false) {
994 if (-1 == ioctl (fd_, TIOCMGET, &status))
997 ss <<
"getDSR failed on a call to ioctl(TIOCMGET): " << errno <<
" " << strerror(errno);
1002 return 0 != (status & TIOCM_DSR);
1009 if (is_open_ ==
false) {
1015 if (-1 == ioctl (fd_, TIOCMGET, &status))
1018 ss <<
"getRI failed on a call to ioctl(TIOCMGET): " << errno <<
" " << strerror(errno);
1023 return 0 != (status & TIOCM_RI);
1030 if (is_open_ ==
false) {
1036 if (-1 == ioctl (fd_, TIOCMGET, &status))
1039 ss <<
"getCD failed on a call to ioctl(TIOCMGET): " << errno <<
" " << strerror(errno);
1044 return 0 != (status & TIOCM_CD);
1051 int result = pthread_mutex_lock(&this->read_mutex);
1060 int result = pthread_mutex_unlock(&this->read_mutex);
1069 int result = pthread_mutex_lock(&this->write_mutex);
1078 int result = pthread_mutex_unlock(&this->write_mutex);
1084 #endif // !defined(_WIN32)