| // |
| // impl/serial_port_base.ipp |
| // ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| // |
| // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
| // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| // |
| |
| #ifndef BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP |
| #define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP |
| |
| #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
| # pragma once |
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
| |
| #include <boost/asio/detail/config.hpp> |
| |
| #if defined(BOOST_ASIO_HAS_SERIAL_PORT) |
| |
| #include <stdexcept> |
| #include <boost/throw_exception.hpp> |
| #include <boost/asio/error.hpp> |
| #include <boost/asio/serial_port_base.hpp> |
| |
| #if defined(GENERATING_DOCUMENTATION) |
| # define BOOST_ASIO_OPTION_STORAGE implementation_defined |
| #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| # define BOOST_ASIO_OPTION_STORAGE DCB |
| #else |
| # define BOOST_ASIO_OPTION_STORAGE termios |
| #endif |
| |
| #include <boost/asio/detail/push_options.hpp> |
| |
| namespace boost { |
| namespace asio { |
| |
| boost::system::error_code serial_port_base::baud_rate::store( |
| BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| storage.BaudRate = value_; |
| #else |
| speed_t baud; |
| switch (value_) |
| { |
| // Do POSIX-specified rates first. |
| case 0: baud = B0; break; |
| case 50: baud = B50; break; |
| case 75: baud = B75; break; |
| case 110: baud = B110; break; |
| case 134: baud = B134; break; |
| case 150: baud = B150; break; |
| case 200: baud = B200; break; |
| case 300: baud = B300; break; |
| case 600: baud = B600; break; |
| case 1200: baud = B1200; break; |
| case 1800: baud = B1800; break; |
| case 2400: baud = B2400; break; |
| case 4800: baud = B4800; break; |
| case 9600: baud = B9600; break; |
| case 19200: baud = B19200; break; |
| case 38400: baud = B38400; break; |
| // And now the extended ones conditionally. |
| # ifdef B7200 |
| case 7200: baud = B7200; break; |
| # endif |
| # ifdef B14400 |
| case 14400: baud = B14400; break; |
| # endif |
| # ifdef B57600 |
| case 57600: baud = B57600; break; |
| # endif |
| # ifdef B115200 |
| case 115200: baud = B115200; break; |
| # endif |
| # ifdef B230400 |
| case 230400: baud = B230400; break; |
| # endif |
| # ifdef B460800 |
| case 460800: baud = B460800; break; |
| # endif |
| # ifdef B500000 |
| case 500000: baud = B500000; break; |
| # endif |
| # ifdef B576000 |
| case 576000: baud = B576000; break; |
| # endif |
| # ifdef B921600 |
| case 921600: baud = B921600; break; |
| # endif |
| # ifdef B1000000 |
| case 1000000: baud = B1000000; break; |
| # endif |
| # ifdef B1152000 |
| case 1152000: baud = B1152000; break; |
| # endif |
| # ifdef B2000000 |
| case 2000000: baud = B2000000; break; |
| # endif |
| # ifdef B3000000 |
| case 3000000: baud = B3000000; break; |
| # endif |
| # ifdef B3500000 |
| case 3500000: baud = B3500000; break; |
| # endif |
| # ifdef B4000000 |
| case 4000000: baud = B4000000; break; |
| # endif |
| default: |
| baud = B0; |
| ec = boost::asio::error::invalid_argument; |
| return ec; |
| } |
| # if defined(_BSD_SOURCE) |
| ::cfsetspeed(&storage, baud); |
| # else |
| ::cfsetispeed(&storage, baud); |
| ::cfsetospeed(&storage, baud); |
| # endif |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| boost::system::error_code serial_port_base::baud_rate::load( |
| const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| value_ = storage.BaudRate; |
| #else |
| speed_t baud = ::cfgetospeed(&storage); |
| switch (baud) |
| { |
| // First do those specified by POSIX. |
| case B0: value_ = 0; break; |
| case B50: value_ = 50; break; |
| case B75: value_ = 75; break; |
| case B110: value_ = 110; break; |
| case B134: value_ = 134; break; |
| case B150: value_ = 150; break; |
| case B200: value_ = 200; break; |
| case B300: value_ = 300; break; |
| case B600: value_ = 600; break; |
| case B1200: value_ = 1200; break; |
| case B1800: value_ = 1800; break; |
| case B2400: value_ = 2400; break; |
| case B4800: value_ = 4800; break; |
| case B9600: value_ = 9600; break; |
| case B19200: value_ = 19200; break; |
| case B38400: value_ = 38400; break; |
| // Now conditionally handle a bunch of extended rates. |
| # ifdef B7200 |
| case B7200: value_ = 7200; break; |
| # endif |
| # ifdef B14400 |
| case B14400: value_ = 14400; break; |
| # endif |
| # ifdef B57600 |
| case B57600: value_ = 57600; break; |
| # endif |
| # ifdef B115200 |
| case B115200: value_ = 115200; break; |
| # endif |
| # ifdef B230400 |
| case B230400: value_ = 230400; break; |
| # endif |
| # ifdef B460800 |
| case B460800: value_ = 460800; break; |
| # endif |
| # ifdef B500000 |
| case B500000: value_ = 500000; break; |
| # endif |
| # ifdef B576000 |
| case B576000: value_ = 576000; break; |
| # endif |
| # ifdef B921600 |
| case B921600: value_ = 921600; break; |
| # endif |
| # ifdef B1000000 |
| case B1000000: value_ = 1000000; break; |
| # endif |
| # ifdef B1152000 |
| case B1152000: value_ = 1152000; break; |
| # endif |
| # ifdef B2000000 |
| case B2000000: value_ = 2000000; break; |
| # endif |
| # ifdef B3000000 |
| case B3000000: value_ = 3000000; break; |
| # endif |
| # ifdef B3500000 |
| case B3500000: value_ = 3500000; break; |
| # endif |
| # ifdef B4000000 |
| case B4000000: value_ = 4000000; break; |
| # endif |
| default: |
| value_ = 0; |
| ec = boost::asio::error::invalid_argument; |
| return ec; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| serial_port_base::flow_control::flow_control( |
| serial_port_base::flow_control::type t) |
| : value_(t) |
| { |
| if (t != none && t != software && t != hardware) |
| { |
| std::out_of_range ex("invalid flow_control value"); |
| boost::throw_exception(ex); |
| } |
| } |
| |
| boost::system::error_code serial_port_base::flow_control::store( |
| BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| storage.fOutxCtsFlow = FALSE; |
| storage.fOutxDsrFlow = FALSE; |
| storage.fTXContinueOnXoff = TRUE; |
| storage.fDtrControl = DTR_CONTROL_ENABLE; |
| storage.fDsrSensitivity = FALSE; |
| storage.fOutX = FALSE; |
| storage.fInX = FALSE; |
| storage.fRtsControl = RTS_CONTROL_ENABLE; |
| switch (value_) |
| { |
| case none: |
| break; |
| case software: |
| storage.fOutX = TRUE; |
| storage.fInX = TRUE; |
| break; |
| case hardware: |
| storage.fOutxCtsFlow = TRUE; |
| storage.fRtsControl = RTS_CONTROL_HANDSHAKE; |
| break; |
| default: |
| break; |
| } |
| #else |
| switch (value_) |
| { |
| case none: |
| storage.c_iflag &= ~(IXOFF | IXON); |
| # if defined(_BSD_SOURCE) |
| storage.c_cflag &= ~CRTSCTS; |
| # elif defined(__QNXNTO__) |
| storage.c_cflag &= ~(IHFLOW | OHFLOW); |
| # endif |
| break; |
| case software: |
| storage.c_iflag |= IXOFF | IXON; |
| # if defined(_BSD_SOURCE) |
| storage.c_cflag &= ~CRTSCTS; |
| # elif defined(__QNXNTO__) |
| storage.c_cflag &= ~(IHFLOW | OHFLOW); |
| # endif |
| break; |
| case hardware: |
| # if defined(_BSD_SOURCE) |
| storage.c_iflag &= ~(IXOFF | IXON); |
| storage.c_cflag |= CRTSCTS; |
| break; |
| # elif defined(__QNXNTO__) |
| storage.c_iflag &= ~(IXOFF | IXON); |
| storage.c_cflag |= (IHFLOW | OHFLOW); |
| break; |
| # else |
| ec = boost::asio::error::operation_not_supported; |
| return ec; |
| # endif |
| default: |
| break; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| boost::system::error_code serial_port_base::flow_control::load( |
| const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| if (storage.fOutX && storage.fInX) |
| { |
| value_ = software; |
| } |
| else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE) |
| { |
| value_ = hardware; |
| } |
| else |
| { |
| value_ = none; |
| } |
| #else |
| if (storage.c_iflag & (IXOFF | IXON)) |
| { |
| value_ = software; |
| } |
| # if defined(_BSD_SOURCE) |
| else if (storage.c_cflag & CRTSCTS) |
| { |
| value_ = hardware; |
| } |
| # elif defined(__QNXNTO__) |
| else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW) |
| { |
| value_ = hardware; |
| } |
| # endif |
| else |
| { |
| value_ = none; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| serial_port_base::parity::parity(serial_port_base::parity::type t) |
| : value_(t) |
| { |
| if (t != none && t != odd && t != even) |
| { |
| std::out_of_range ex("invalid parity value"); |
| boost::throw_exception(ex); |
| } |
| } |
| |
| boost::system::error_code serial_port_base::parity::store( |
| BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| switch (value_) |
| { |
| case none: |
| storage.fParity = FALSE; |
| storage.Parity = NOPARITY; |
| break; |
| case odd: |
| storage.fParity = TRUE; |
| storage.Parity = ODDPARITY; |
| break; |
| case even: |
| storage.fParity = TRUE; |
| storage.Parity = EVENPARITY; |
| break; |
| default: |
| break; |
| } |
| #else |
| switch (value_) |
| { |
| case none: |
| storage.c_iflag |= IGNPAR; |
| storage.c_cflag &= ~(PARENB | PARODD); |
| break; |
| case even: |
| storage.c_iflag &= ~(IGNPAR | PARMRK); |
| storage.c_iflag |= INPCK; |
| storage.c_cflag |= PARENB; |
| storage.c_cflag &= ~PARODD; |
| break; |
| case odd: |
| storage.c_iflag &= ~(IGNPAR | PARMRK); |
| storage.c_iflag |= INPCK; |
| storage.c_cflag |= (PARENB | PARODD); |
| break; |
| default: |
| break; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| boost::system::error_code serial_port_base::parity::load( |
| const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| if (storage.Parity == EVENPARITY) |
| { |
| value_ = even; |
| } |
| else if (storage.Parity == ODDPARITY) |
| { |
| value_ = odd; |
| } |
| else |
| { |
| value_ = none; |
| } |
| #else |
| if (storage.c_cflag & PARENB) |
| { |
| if (storage.c_cflag & PARODD) |
| { |
| value_ = odd; |
| } |
| else |
| { |
| value_ = even; |
| } |
| } |
| else |
| { |
| value_ = none; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| serial_port_base::stop_bits::stop_bits( |
| serial_port_base::stop_bits::type t) |
| : value_(t) |
| { |
| if (t != one && t != onepointfive && t != two) |
| { |
| std::out_of_range ex("invalid stop_bits value"); |
| boost::throw_exception(ex); |
| } |
| } |
| |
| boost::system::error_code serial_port_base::stop_bits::store( |
| BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| switch (value_) |
| { |
| case one: |
| storage.StopBits = ONESTOPBIT; |
| break; |
| case onepointfive: |
| storage.StopBits = ONE5STOPBITS; |
| break; |
| case two: |
| storage.StopBits = TWOSTOPBITS; |
| break; |
| default: |
| break; |
| } |
| #else |
| switch (value_) |
| { |
| case one: |
| storage.c_cflag &= ~CSTOPB; |
| break; |
| case two: |
| storage.c_cflag |= CSTOPB; |
| break; |
| default: |
| ec = boost::asio::error::operation_not_supported; |
| return ec; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| boost::system::error_code serial_port_base::stop_bits::load( |
| const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| if (storage.StopBits == ONESTOPBIT) |
| { |
| value_ = one; |
| } |
| else if (storage.StopBits == ONE5STOPBITS) |
| { |
| value_ = onepointfive; |
| } |
| else if (storage.StopBits == TWOSTOPBITS) |
| { |
| value_ = two; |
| } |
| else |
| { |
| value_ = one; |
| } |
| #else |
| value_ = (storage.c_cflag & CSTOPB) ? two : one; |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| serial_port_base::character_size::character_size(unsigned int t) |
| : value_(t) |
| { |
| if (t < 5 || t > 8) |
| { |
| std::out_of_range ex("invalid character_size value"); |
| boost::throw_exception(ex); |
| } |
| } |
| |
| boost::system::error_code serial_port_base::character_size::store( |
| BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| storage.ByteSize = value_; |
| #else |
| storage.c_cflag &= ~CSIZE; |
| switch (value_) |
| { |
| case 5: storage.c_cflag |= CS5; break; |
| case 6: storage.c_cflag |= CS6; break; |
| case 7: storage.c_cflag |= CS7; break; |
| case 8: storage.c_cflag |= CS8; break; |
| default: break; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| boost::system::error_code serial_port_base::character_size::load( |
| const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) |
| { |
| #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) |
| value_ = storage.ByteSize; |
| #else |
| if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; } |
| else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; } |
| else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; } |
| else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; } |
| else |
| { |
| // Hmmm, use 8 for now. |
| value_ = 8; |
| } |
| #endif |
| ec = boost::system::error_code(); |
| return ec; |
| } |
| |
| } // namespace asio |
| } // namespace boost |
| |
| #include <boost/asio/detail/pop_options.hpp> |
| |
| #undef BOOST_ASIO_OPTION_STORAGE |
| |
| #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) |
| |
| #endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP |