1// 2// detail/impl/reactive_serial_port_service.ipp 3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4// 5// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6// Copyright (c) 2008 Rep Invariant Systems, Inc. ([email protected]) 7// 8// Distributed under the Boost Software License, Version 1.0. (See accompanying 9// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10// 11 12#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP 13#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP 14 15#if defined(_MSC_VER) && (_MSC_VER >= 1200) 16# pragma once 17#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 18 19#include <boost/asio/detail/config.hpp> 20 21#if defined(BOOST_ASIO_HAS_SERIAL_PORT) 22#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) 23 24#include <cstring> 25#include <boost/asio/detail/reactive_serial_port_service.hpp> 26 27#include <boost/asio/detail/push_options.hpp> 28 29namespace boost { 30namespace asio { 31namespace detail { 32 33reactive_serial_port_service::reactive_serial_port_service( 34 execution_context& context) 35 : execution_context_service_base<reactive_serial_port_service>(context), 36 descriptor_service_(context) 37{ 38} 39 40void reactive_serial_port_service::shutdown() 41{ 42 descriptor_service_.shutdown(); 43} 44 45boost::system::error_code reactive_serial_port_service::open( 46 reactive_serial_port_service::implementation_type& impl, 47 const std::string& device, boost::system::error_code& ec) 48{ 49 if (is_open(impl)) 50 { 51 ec = boost::asio::error::already_open; 52 return ec; 53 } 54 55 descriptor_ops::state_type state = 0; 56 int fd = descriptor_ops::open(device.c_str(), 57 O_RDWR | O_NONBLOCK | O_NOCTTY, ec); 58 if (fd < 0) 59 return ec; 60 61 int s = descriptor_ops::fcntl(fd, F_GETFL, ec); 62 if (s >= 0) 63 s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); 64 if (s < 0) 65 { 66 boost::system::error_code ignored_ec; 67 descriptor_ops::close(fd, state, ignored_ec); 68 return ec; 69 } 70 71 // Set up default serial port options. 72 termios ios; 73 s = ::tcgetattr(fd, &ios); 74 descriptor_ops::get_last_error(ec, s < 0); 75 if (s >= 0) 76 { 77#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) 78 ::cfmakeraw(&ios); 79#else 80 ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK 81 | ISTRIP | INLCR | IGNCR | ICRNL | IXON); 82 ios.c_oflag &= ~OPOST; 83 ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 84 ios.c_cflag &= ~(CSIZE | PARENB); 85 ios.c_cflag |= CS8; 86#endif 87 ios.c_iflag |= IGNPAR; 88 ios.c_cflag |= CREAD | CLOCAL; 89 s = ::tcsetattr(fd, TCSANOW, &ios); 90 descriptor_ops::get_last_error(ec, s < 0); 91 } 92 if (s < 0) 93 { 94 boost::system::error_code ignored_ec; 95 descriptor_ops::close(fd, state, ignored_ec); 96 return ec; 97 } 98 99 // We're done. Take ownership of the serial port descriptor. 100 if (descriptor_service_.assign(impl, fd, ec)) 101 { 102 boost::system::error_code ignored_ec; 103 descriptor_ops::close(fd, state, ignored_ec); 104 } 105 106 return ec; 107} 108 109boost::system::error_code reactive_serial_port_service::do_set_option( 110 reactive_serial_port_service::implementation_type& impl, 111 reactive_serial_port_service::store_function_type store, 112 const void* option, boost::system::error_code& ec) 113{ 114 termios ios; 115 int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); 116 descriptor_ops::get_last_error(ec, s < 0); 117 if (s < 0) 118 return ec; 119 120 if (store(option, ios, ec)) 121 return ec; 122 123 s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios); 124 descriptor_ops::get_last_error(ec, s < 0); 125 return ec; 126} 127 128boost::system::error_code reactive_serial_port_service::do_get_option( 129 const reactive_serial_port_service::implementation_type& impl, 130 reactive_serial_port_service::load_function_type load, 131 void* option, boost::system::error_code& ec) const 132{ 133 termios ios; 134 int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); 135 descriptor_ops::get_last_error(ec, s < 0); 136 if (s < 0) 137 return ec; 138 139 return load(option, ios, ec); 140} 141 142} // namespace detail 143} // namespace asio 144} // namespace boost 145 146#include <boost/asio/detail/pop_options.hpp> 147 148#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) 149#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) 150 151#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP 152