1 // 2 // detail/reactive_serial_port_service.hpp 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_REACTIVE_SERIAL_PORT_SERVICE_HPP 13 #define BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP 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 <string> 25 #include <boost/asio/error.hpp> 26 #include <boost/asio/execution_context.hpp> 27 #include <boost/asio/serial_port_base.hpp> 28 #include <boost/asio/detail/descriptor_ops.hpp> 29 #include <boost/asio/detail/reactive_descriptor_service.hpp> 30 31 #include <boost/asio/detail/push_options.hpp> 32 33 namespace boost { 34 namespace asio { 35 namespace detail { 36 37 // Extend reactive_descriptor_service to provide serial port support. 38 class reactive_serial_port_service : 39 public execution_context_service_base<reactive_serial_port_service> 40 { 41 public: 42 // The native type of a serial port. 43 typedef reactive_descriptor_service::native_handle_type native_handle_type; 44 45 // The implementation type of the serial port. 46 typedef reactive_descriptor_service::implementation_type implementation_type; 47 48 BOOST_ASIO_DECL reactive_serial_port_service(execution_context& context); 49 50 // Destroy all user-defined handler objects owned by the service. 51 BOOST_ASIO_DECL void shutdown(); 52 53 // Construct a new serial port implementation. construct(implementation_type & impl)54 void construct(implementation_type& impl) 55 { 56 descriptor_service_.construct(impl); 57 } 58 59 // Move-construct a new serial port implementation. move_construct(implementation_type & impl,implementation_type & other_impl)60 void move_construct(implementation_type& impl, 61 implementation_type& other_impl) 62 { 63 descriptor_service_.move_construct(impl, other_impl); 64 } 65 66 // Move-assign from another serial port implementation. move_assign(implementation_type & impl,reactive_serial_port_service & other_service,implementation_type & other_impl)67 void move_assign(implementation_type& impl, 68 reactive_serial_port_service& other_service, 69 implementation_type& other_impl) 70 { 71 descriptor_service_.move_assign(impl, 72 other_service.descriptor_service_, other_impl); 73 } 74 75 // Destroy a serial port implementation. destroy(implementation_type & impl)76 void destroy(implementation_type& impl) 77 { 78 descriptor_service_.destroy(impl); 79 } 80 81 // Open the serial port using the specified device name. 82 BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, 83 const std::string& device, boost::system::error_code& ec); 84 85 // Assign a native descriptor to a serial port implementation. assign(implementation_type & impl,const native_handle_type & native_descriptor,boost::system::error_code & ec)86 boost::system::error_code assign(implementation_type& impl, 87 const native_handle_type& native_descriptor, 88 boost::system::error_code& ec) 89 { 90 return descriptor_service_.assign(impl, native_descriptor, ec); 91 } 92 93 // Determine whether the serial port is open. is_open(const implementation_type & impl) const94 bool is_open(const implementation_type& impl) const 95 { 96 return descriptor_service_.is_open(impl); 97 } 98 99 // Destroy a serial port implementation. close(implementation_type & impl,boost::system::error_code & ec)100 boost::system::error_code close(implementation_type& impl, 101 boost::system::error_code& ec) 102 { 103 return descriptor_service_.close(impl, ec); 104 } 105 106 // Get the native serial port representation. native_handle(implementation_type & impl)107 native_handle_type native_handle(implementation_type& impl) 108 { 109 return descriptor_service_.native_handle(impl); 110 } 111 112 // Cancel all operations associated with the serial port. cancel(implementation_type & impl,boost::system::error_code & ec)113 boost::system::error_code cancel(implementation_type& impl, 114 boost::system::error_code& ec) 115 { 116 return descriptor_service_.cancel(impl, ec); 117 } 118 119 // Set an option on the serial port. 120 template <typename SettableSerialPortOption> set_option(implementation_type & impl,const SettableSerialPortOption & option,boost::system::error_code & ec)121 boost::system::error_code set_option(implementation_type& impl, 122 const SettableSerialPortOption& option, boost::system::error_code& ec) 123 { 124 return do_set_option(impl, 125 &reactive_serial_port_service::store_option<SettableSerialPortOption>, 126 &option, ec); 127 } 128 129 // Get an option from the serial port. 130 template <typename GettableSerialPortOption> get_option(const implementation_type & impl,GettableSerialPortOption & option,boost::system::error_code & ec) const131 boost::system::error_code get_option(const implementation_type& impl, 132 GettableSerialPortOption& option, boost::system::error_code& ec) const 133 { 134 return do_get_option(impl, 135 &reactive_serial_port_service::load_option<GettableSerialPortOption>, 136 &option, ec); 137 } 138 139 // Send a break sequence to the serial port. send_break(implementation_type & impl,boost::system::error_code & ec)140 boost::system::error_code send_break(implementation_type& impl, 141 boost::system::error_code& ec) 142 { 143 int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0); 144 descriptor_ops::get_last_error(ec, result < 0); 145 return ec; 146 } 147 148 // Write the given data. Returns the number of bytes sent. 149 template <typename ConstBufferSequence> write_some(implementation_type & impl,const ConstBufferSequence & buffers,boost::system::error_code & ec)150 size_t write_some(implementation_type& impl, 151 const ConstBufferSequence& buffers, boost::system::error_code& ec) 152 { 153 return descriptor_service_.write_some(impl, buffers, ec); 154 } 155 156 // Start an asynchronous write. The data being written must be valid for the 157 // lifetime of the asynchronous operation. 158 template <typename ConstBufferSequence, typename Handler, typename IoExecutor> async_write_some(implementation_type & impl,const ConstBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)159 void async_write_some(implementation_type& impl, 160 const ConstBufferSequence& buffers, 161 Handler& handler, const IoExecutor& io_ex) 162 { 163 descriptor_service_.async_write_some(impl, buffers, handler, io_ex); 164 } 165 166 // Read some data. Returns the number of bytes received. 167 template <typename MutableBufferSequence> read_some(implementation_type & impl,const MutableBufferSequence & buffers,boost::system::error_code & ec)168 size_t read_some(implementation_type& impl, 169 const MutableBufferSequence& buffers, boost::system::error_code& ec) 170 { 171 return descriptor_service_.read_some(impl, buffers, ec); 172 } 173 174 // Start an asynchronous read. The buffer for the data being received must be 175 // valid for the lifetime of the asynchronous operation. 176 template <typename MutableBufferSequence, 177 typename Handler, typename IoExecutor> async_read_some(implementation_type & impl,const MutableBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)178 void async_read_some(implementation_type& impl, 179 const MutableBufferSequence& buffers, 180 Handler& handler, const IoExecutor& io_ex) 181 { 182 descriptor_service_.async_read_some(impl, buffers, handler, io_ex); 183 } 184 185 private: 186 // Function pointer type for storing a serial port option. 187 typedef boost::system::error_code (*store_function_type)( 188 const void*, termios&, boost::system::error_code&); 189 190 // Helper function template to store a serial port option. 191 template <typename SettableSerialPortOption> store_option(const void * option,termios & storage,boost::system::error_code & ec)192 static boost::system::error_code store_option(const void* option, 193 termios& storage, boost::system::error_code& ec) 194 { 195 static_cast<const SettableSerialPortOption*>(option)->store(storage, ec); 196 return ec; 197 } 198 199 // Helper function to set a serial port option. 200 BOOST_ASIO_DECL boost::system::error_code do_set_option( 201 implementation_type& impl, store_function_type store, 202 const void* option, boost::system::error_code& ec); 203 204 // Function pointer type for loading a serial port option. 205 typedef boost::system::error_code (*load_function_type)( 206 void*, const termios&, boost::system::error_code&); 207 208 // Helper function template to load a serial port option. 209 template <typename GettableSerialPortOption> load_option(void * option,const termios & storage,boost::system::error_code & ec)210 static boost::system::error_code load_option(void* option, 211 const termios& storage, boost::system::error_code& ec) 212 { 213 static_cast<GettableSerialPortOption*>(option)->load(storage, ec); 214 return ec; 215 } 216 217 // Helper function to get a serial port option. 218 BOOST_ASIO_DECL boost::system::error_code do_get_option( 219 const implementation_type& impl, load_function_type load, 220 void* option, boost::system::error_code& ec) const; 221 222 // The implementation used for initiating asynchronous operations. 223 reactive_descriptor_service descriptor_service_; 224 }; 225 226 } // namespace detail 227 } // namespace asio 228 } // namespace boost 229 230 #include <boost/asio/detail/pop_options.hpp> 231 232 #if defined(BOOST_ASIO_HEADER_ONLY) 233 # include <boost/asio/detail/impl/reactive_serial_port_service.ipp> 234 #endif // defined(BOOST_ASIO_HEADER_ONLY) 235 236 #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) 237 #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) 238 239 #endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP 240