Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / asio / detail / impl / reactive_serial_port_service.ipp
1 //
2 // detail/impl/reactive_serial_port_service.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
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
29 namespace boost {
30 namespace asio {
31 namespace detail {
32
33 reactive_serial_port_service::reactive_serial_port_service(
34     boost::asio::io_service& io_service)
35   : descriptor_service_(io_service)
36 {
37 }
38
39 void reactive_serial_port_service::shutdown_service()
40 {
41   descriptor_service_.shutdown_service();
42 }
43
44 boost::system::error_code reactive_serial_port_service::open(
45     reactive_serial_port_service::implementation_type& impl,
46     const std::string& device, boost::system::error_code& ec)
47 {
48   if (is_open(impl))
49   {
50     ec = boost::asio::error::already_open;
51     return ec;
52   }
53
54   descriptor_ops::state_type state = 0;
55   int fd = descriptor_ops::open(device.c_str(),
56       O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
57   if (fd < 0)
58     return ec;
59
60   int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
61   if (s >= 0)
62     s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
63   if (s < 0)
64   {
65     boost::system::error_code ignored_ec;
66     descriptor_ops::close(fd, state, ignored_ec);
67     return ec;
68   }
69
70   // Set up default serial port options.
71   termios ios;
72   errno = 0;
73   s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
74   if (s >= 0)
75   {
76 #if defined(_BSD_SOURCE)
77     ::cfmakeraw(&ios);
78 #else
79     ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
80         | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
81     ios.c_oflag &= ~OPOST;
82     ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
83     ios.c_cflag &= ~(CSIZE | PARENB);
84     ios.c_cflag |= CS8;
85 #endif
86     ios.c_iflag |= IGNPAR;
87     ios.c_cflag |= CREAD | CLOCAL;
88     errno = 0;
89     s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
90   }
91   if (s < 0)
92   {
93     boost::system::error_code ignored_ec;
94     descriptor_ops::close(fd, state, ignored_ec);
95     return ec;
96   }
97
98   // We're done. Take ownership of the serial port descriptor.
99   if (descriptor_service_.assign(impl, fd, ec))
100   {
101     boost::system::error_code ignored_ec;
102     descriptor_ops::close(fd, state, ignored_ec);
103   }
104
105   return ec;
106 }
107
108 boost::system::error_code reactive_serial_port_service::do_set_option(
109     reactive_serial_port_service::implementation_type& impl,
110     reactive_serial_port_service::store_function_type store,
111     const void* option, boost::system::error_code& ec)
112 {
113   termios ios;
114   errno = 0;
115   descriptor_ops::error_wrapper(::tcgetattr(
116         descriptor_service_.native_handle(impl), &ios), ec);
117   if (ec)
118     return ec;
119
120   if (store(option, ios, ec))
121     return ec;
122
123   errno = 0;
124   descriptor_ops::error_wrapper(::tcsetattr(
125         descriptor_service_.native_handle(impl), TCSANOW, &ios), ec);
126   return ec;
127 }
128
129 boost::system::error_code reactive_serial_port_service::do_get_option(
130     const reactive_serial_port_service::implementation_type& impl,
131     reactive_serial_port_service::load_function_type load,
132     void* option, boost::system::error_code& ec) const
133 {
134   termios ios;
135   errno = 0;
136   descriptor_ops::error_wrapper(::tcgetattr(
137         descriptor_service_.native_handle(impl), &ios), ec);
138   if (ec)
139     return ec;
140
141   return load(option, ios, ec);
142 }
143
144 } // namespace detail
145 } // namespace asio
146 } // namespace boost
147
148 #include <boost/asio/detail/pop_options.hpp>
149
150 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__)
151 #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
152
153 #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP