$search
00001 // 00002 // reactive_serial_port_service.hpp 00003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00004 // 00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) 00006 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) 00007 // 00008 // Distributed under the Boost Software License, Version 1.0. (See accompanying 00009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 00010 // 00011 00012 #ifndef ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP 00013 #define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP 00014 00015 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 00016 # pragma once 00017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 00018 00019 #include "asio/detail/push_options.hpp" 00020 00021 #include "asio/detail/push_options.hpp" 00022 #include <cstring> 00023 #include <string> 00024 #include "asio/detail/pop_options.hpp" 00025 00026 #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) 00027 00028 #include "asio/detail/push_options.hpp" 00029 #include <termios.h> 00030 #include "asio/detail/pop_options.hpp" 00031 00032 #include "asio/error.hpp" 00033 #include "asio/io_service.hpp" 00034 #include "asio/detail/descriptor_ops.hpp" 00035 #include "asio/detail/reactive_descriptor_service.hpp" 00036 00037 namespace asio { 00038 namespace detail { 00039 00040 // Extend reactive_descriptor_service to provide serial port support. 00041 template <typename Reactor> 00042 class reactive_serial_port_service 00043 : public asio::detail::service_base< 00044 reactive_serial_port_service<Reactor> > 00045 { 00046 public: 00047 // The native type of a stream handle. 00048 typedef typename reactive_descriptor_service<Reactor>::native_type 00049 native_type; 00050 00051 // The implementation type of the stream handle. 00052 typedef typename reactive_descriptor_service<Reactor>::implementation_type 00053 implementation_type; 00054 00055 reactive_serial_port_service(asio::io_service& io_service) 00056 : asio::detail::service_base< 00057 reactive_serial_port_service>(io_service), 00058 descriptor_service_(asio::use_service< 00059 reactive_descriptor_service<Reactor> >(io_service)) 00060 { 00061 } 00062 00063 // Destroy all user-defined handler objects owned by the service. 00064 void shutdown_service() 00065 { 00066 } 00067 00068 // Construct a new handle implementation. 00069 void construct(implementation_type& impl) 00070 { 00071 descriptor_service_.construct(impl); 00072 } 00073 00074 // Destroy a handle implementation. 00075 void destroy(implementation_type& impl) 00076 { 00077 descriptor_service_.destroy(impl); 00078 } 00079 00080 // Open the serial port using the specified device name. 00081 asio::error_code open(implementation_type& impl, 00082 const std::string& device, asio::error_code& ec) 00083 { 00084 if (is_open(impl)) 00085 { 00086 ec = asio::error::already_open; 00087 return ec; 00088 } 00089 00090 int fd = descriptor_ops::open(device.c_str(), 00091 O_RDWR | O_NONBLOCK | O_NOCTTY, ec); 00092 if (fd < 0) 00093 return ec; 00094 00095 int s = descriptor_ops::fcntl(fd, F_GETFL, ec); 00096 if (s >= 0) 00097 s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); 00098 if (s < 0) 00099 { 00100 asio::error_code ignored_ec; 00101 descriptor_ops::close(fd, ignored_ec); 00102 return ec; 00103 } 00104 00105 // Set up default serial port options. 00106 termios ios; 00107 descriptor_ops::clear_error(ec); 00108 s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); 00109 if (s >= 0) 00110 { 00111 #if defined(_BSD_SOURCE) 00112 ::cfmakeraw(&ios); 00113 #else 00114 ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK 00115 | ISTRIP | INLCR | IGNCR | ICRNL | IXON); 00116 ios.c_oflag &= ~OPOST; 00117 ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 00118 ios.c_cflag &= ~(CSIZE | PARENB); 00119 ios.c_cflag |= CS8; 00120 #endif 00121 ios.c_iflag |= IGNPAR; 00122 ios.c_cflag |= CREAD | CLOCAL; 00123 descriptor_ops::clear_error(ec); 00124 s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); 00125 } 00126 if (s < 0) 00127 { 00128 asio::error_code ignored_ec; 00129 descriptor_ops::close(fd, ignored_ec); 00130 return ec; 00131 } 00132 00133 // We're done. Take ownership of the serial port descriptor. 00134 if (descriptor_service_.assign(impl, fd, ec)) 00135 { 00136 asio::error_code ignored_ec; 00137 descriptor_ops::close(fd, ignored_ec); 00138 } 00139 00140 return ec; 00141 } 00142 00143 // Assign a native handle to a handle implementation. 00144 asio::error_code assign(implementation_type& impl, 00145 const native_type& native_descriptor, asio::error_code& ec) 00146 { 00147 return descriptor_service_.assign(impl, native_descriptor, ec); 00148 } 00149 00150 // Determine whether the handle is open. 00151 bool is_open(const implementation_type& impl) const 00152 { 00153 return descriptor_service_.is_open(impl); 00154 } 00155 00156 // Destroy a handle implementation. 00157 asio::error_code close(implementation_type& impl, 00158 asio::error_code& ec) 00159 { 00160 return descriptor_service_.close(impl, ec); 00161 } 00162 00163 // Get the native handle representation. 00164 native_type native(implementation_type& impl) 00165 { 00166 return descriptor_service_.native(impl); 00167 } 00168 00169 // Cancel all operations associated with the handle. 00170 asio::error_code cancel(implementation_type& impl, 00171 asio::error_code& ec) 00172 { 00173 return descriptor_service_.cancel(impl, ec); 00174 } 00175 00176 // Set an option on the serial port. 00177 template <typename SettableSerialPortOption> 00178 asio::error_code set_option(implementation_type& impl, 00179 const SettableSerialPortOption& option, asio::error_code& ec) 00180 { 00181 termios ios; 00182 descriptor_ops::clear_error(ec); 00183 descriptor_ops::error_wrapper(::tcgetattr( 00184 descriptor_service_.native(impl), &ios), ec); 00185 if (ec) 00186 return ec; 00187 00188 if (option.store(ios, ec)) 00189 return ec; 00190 00191 descriptor_ops::clear_error(ec); 00192 descriptor_ops::error_wrapper(::tcsetattr( 00193 descriptor_service_.native(impl), TCSANOW, &ios), ec); 00194 return ec; 00195 } 00196 00197 // Get an option from the serial port. 00198 template <typename GettableSerialPortOption> 00199 asio::error_code get_option(const implementation_type& impl, 00200 GettableSerialPortOption& option, asio::error_code& ec) const 00201 { 00202 termios ios; 00203 descriptor_ops::clear_error(ec); 00204 descriptor_ops::error_wrapper(::tcgetattr( 00205 descriptor_service_.native(impl), &ios), ec); 00206 if (ec) 00207 return ec; 00208 00209 return option.load(ios, ec); 00210 } 00211 00212 // Send a break sequence to the serial port. 00213 asio::error_code send_break(implementation_type& impl, 00214 asio::error_code& ec) 00215 { 00216 descriptor_ops::clear_error(ec); 00217 descriptor_ops::error_wrapper(::tcsendbreak( 00218 descriptor_service_.native(impl), 0), ec); 00219 return ec; 00220 } 00221 00222 // Write the given data. Returns the number of bytes sent. 00223 template <typename ConstBufferSequence> 00224 size_t write_some(implementation_type& impl, 00225 const ConstBufferSequence& buffers, asio::error_code& ec) 00226 { 00227 return descriptor_service_.write_some(impl, buffers, ec); 00228 } 00229 00230 // Start an asynchronous write. The data being written must be valid for the 00231 // lifetime of the asynchronous operation. 00232 template <typename ConstBufferSequence, typename Handler> 00233 void async_write_some(implementation_type& impl, 00234 const ConstBufferSequence& buffers, Handler handler) 00235 { 00236 descriptor_service_.async_write_some(impl, buffers, handler); 00237 } 00238 00239 // Read some data. Returns the number of bytes received. 00240 template <typename MutableBufferSequence> 00241 size_t read_some(implementation_type& impl, 00242 const MutableBufferSequence& buffers, asio::error_code& ec) 00243 { 00244 return descriptor_service_.read_some(impl, buffers, ec); 00245 } 00246 00247 // Start an asynchronous read. The buffer for the data being received must be 00248 // valid for the lifetime of the asynchronous operation. 00249 template <typename MutableBufferSequence, typename Handler> 00250 void async_read_some(implementation_type& impl, 00251 const MutableBufferSequence& buffers, Handler handler) 00252 { 00253 descriptor_service_.async_read_some(impl, buffers, handler); 00254 } 00255 00256 private: 00257 // The handle service used for initiating asynchronous operations. 00258 reactive_descriptor_service<Reactor>& descriptor_service_; 00259 }; 00260 00261 } // namespace detail 00262 } // namespace asio 00263 00264 #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) 00265 00266 #include "asio/detail/pop_options.hpp" 00267 00268 #endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP