1 | // |
2 | // detail/impl/reactive_serial_port_service.ipp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2015 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(path: 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(d: fd, F_GETFL, ec); |
61 | if (s >= 0) |
62 | s = descriptor_ops::fcntl(d: fd, F_SETFL, arg: s | O_NONBLOCK, ec); |
63 | if (s < 0) |
64 | { |
65 | boost::system::error_code ignored_ec; |
66 | descriptor_ops::close(d: fd, state, ec&: 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(return_value: ::tcgetattr(fd: fd, termios_p: &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(return_value: ::tcsetattr(fd: fd, TCSANOW, termios_p: &ios), ec); |
90 | } |
91 | if (s < 0) |
92 | { |
93 | boost::system::error_code ignored_ec; |
94 | descriptor_ops::close(d: fd, state, ec&: ignored_ec); |
95 | return ec; |
96 | } |
97 | |
98 | // We're done. Take ownership of the serial port descriptor. |
99 | if (descriptor_service_.assign(impl, native_descriptor: fd, ec)) |
100 | { |
101 | boost::system::error_code ignored_ec; |
102 | descriptor_ops::close(d: fd, state, ec&: 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(return_value: ::tcgetattr( |
116 | fd: descriptor_service_.native_handle(impl), termios_p: &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(return_value: ::tcsetattr( |
125 | fd: descriptor_service_.native_handle(impl), TCSANOW, termios_p: &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(return_value: ::tcgetattr( |
137 | fd: descriptor_service_.native_handle(impl), termios_p: &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 |
154 | |