$search
00001 // 00002 // win_iocp_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_WIN_IOCP_SERIAL_PORT_SERVICE_HPP 00013 #define ASIO_DETAIL_WIN_IOCP_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 #include "asio/detail/win_iocp_io_service_fwd.hpp" 00027 00028 #if defined(ASIO_HAS_IOCP) 00029 00030 #include "asio/error.hpp" 00031 #include "asio/io_service.hpp" 00032 #include "asio/detail/win_iocp_handle_service.hpp" 00033 00034 namespace asio { 00035 namespace detail { 00036 00037 // Extend win_iocp_handle_service to provide serial port support. 00038 class win_iocp_serial_port_service 00039 : public asio::detail::service_base<win_iocp_serial_port_service> 00040 { 00041 public: 00042 // The native type of a stream handle. 00043 typedef win_iocp_handle_service::native_type native_type; 00044 00045 // The implementation type of the stream handle. 00046 typedef win_iocp_handle_service::implementation_type implementation_type; 00047 00048 win_iocp_serial_port_service(asio::io_service& io_service) 00049 : asio::detail::service_base< 00050 win_iocp_serial_port_service>(io_service), 00051 handle_service_( 00052 asio::use_service<win_iocp_handle_service>(io_service)) 00053 { 00054 } 00055 00056 // Destroy all user-defined handler objects owned by the service. 00057 void shutdown_service() 00058 { 00059 } 00060 00061 // Construct a new handle implementation. 00062 void construct(implementation_type& impl) 00063 { 00064 handle_service_.construct(impl); 00065 } 00066 00067 // Destroy a handle implementation. 00068 void destroy(implementation_type& impl) 00069 { 00070 handle_service_.destroy(impl); 00071 } 00072 00073 // Open the serial port using the specified device name. 00074 asio::error_code open(implementation_type& impl, 00075 const std::string& device, asio::error_code& ec) 00076 { 00077 if (is_open(impl)) 00078 { 00079 ec = asio::error::already_open; 00080 return ec; 00081 } 00082 00083 // For convenience, add a leading \\.\ sequence if not already present. 00084 std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; 00085 00086 // Open a handle to the serial port. 00087 ::HANDLE handle = ::CreateFileA(name.c_str(), 00088 GENERIC_READ | GENERIC_WRITE, 0, 0, 00089 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); 00090 if (handle == INVALID_HANDLE_VALUE) 00091 { 00092 DWORD last_error = ::GetLastError(); 00093 ec = asio::error_code(last_error, 00094 asio::error::get_system_category()); 00095 return ec; 00096 } 00097 00098 // Determine the initial serial port parameters. 00099 using namespace std; // For memcpy. 00100 ::DCB dcb; 00101 memset(&dcb, 0, sizeof(DCB)); 00102 dcb.DCBlength = sizeof(DCB); 00103 if (!::GetCommState(handle, &dcb)) 00104 { 00105 DWORD last_error = ::GetLastError(); 00106 ::CloseHandle(handle); 00107 ec = asio::error_code(last_error, 00108 asio::error::get_system_category()); 00109 return ec; 00110 } 00111 00112 // Set some default serial port parameters. This implementation does not 00113 // support changing these, so they might as well be in a known state. 00114 dcb.fBinary = TRUE; // Win32 only supports binary mode. 00115 dcb.fDsrSensitivity = FALSE; 00116 dcb.fNull = FALSE; // Do not ignore NULL characters. 00117 dcb.fAbortOnError = FALSE; // Ignore serial framing errors. 00118 if (!::SetCommState(handle, &dcb)) 00119 { 00120 DWORD last_error = ::GetLastError(); 00121 ::CloseHandle(handle); 00122 ec = asio::error_code(last_error, 00123 asio::error::get_system_category()); 00124 return ec; 00125 } 00126 00127 // Set up timeouts so that the serial port will behave similarly to a 00128 // network socket. Reads wait for at least one byte, then return with 00129 // whatever they have. Writes return once everything is out the door. 00130 ::COMMTIMEOUTS timeouts; 00131 timeouts.ReadIntervalTimeout = 1; 00132 timeouts.ReadTotalTimeoutMultiplier = 0; 00133 timeouts.ReadTotalTimeoutConstant = 0; 00134 timeouts.WriteTotalTimeoutMultiplier = 0; 00135 timeouts.WriteTotalTimeoutConstant = 0; 00136 if (!::SetCommTimeouts(handle, &timeouts)) 00137 { 00138 DWORD last_error = ::GetLastError(); 00139 ::CloseHandle(handle); 00140 ec = asio::error_code(last_error, 00141 asio::error::get_system_category()); 00142 return ec; 00143 } 00144 00145 // We're done. Take ownership of the serial port handle. 00146 if (handle_service_.assign(impl, handle, ec)) 00147 ::CloseHandle(handle); 00148 return ec; 00149 } 00150 00151 // Assign a native handle to a handle implementation. 00152 asio::error_code assign(implementation_type& impl, 00153 const native_type& native_handle, asio::error_code& ec) 00154 { 00155 return handle_service_.assign(impl, native_handle, ec); 00156 } 00157 00158 // Determine whether the handle is open. 00159 bool is_open(const implementation_type& impl) const 00160 { 00161 return handle_service_.is_open(impl); 00162 } 00163 00164 // Destroy a handle implementation. 00165 asio::error_code close(implementation_type& impl, 00166 asio::error_code& ec) 00167 { 00168 return handle_service_.close(impl, ec); 00169 } 00170 00171 // Get the native handle representation. 00172 native_type native(implementation_type& impl) 00173 { 00174 return handle_service_.native(impl); 00175 } 00176 00177 // Cancel all operations associated with the handle. 00178 asio::error_code cancel(implementation_type& impl, 00179 asio::error_code& ec) 00180 { 00181 return handle_service_.cancel(impl, ec); 00182 } 00183 00184 // Set an option on the serial port. 00185 template <typename SettableSerialPortOption> 00186 asio::error_code set_option(implementation_type& impl, 00187 const SettableSerialPortOption& option, asio::error_code& ec) 00188 { 00189 using namespace std; // For memcpy. 00190 00191 ::DCB dcb; 00192 memset(&dcb, 0, sizeof(DCB)); 00193 dcb.DCBlength = sizeof(DCB); 00194 if (!::GetCommState(handle_service_.native(impl), &dcb)) 00195 { 00196 DWORD last_error = ::GetLastError(); 00197 ec = asio::error_code(last_error, 00198 asio::error::get_system_category()); 00199 return ec; 00200 } 00201 00202 if (option.store(dcb, ec)) 00203 return ec; 00204 00205 if (!::SetCommState(handle_service_.native(impl), &dcb)) 00206 { 00207 DWORD last_error = ::GetLastError(); 00208 ec = asio::error_code(last_error, 00209 asio::error::get_system_category()); 00210 return ec; 00211 } 00212 00213 ec = asio::error_code(); 00214 return ec; 00215 } 00216 00217 // Get an option from the serial port. 00218 template <typename GettableSerialPortOption> 00219 asio::error_code get_option(const implementation_type& impl, 00220 GettableSerialPortOption& option, asio::error_code& ec) const 00221 { 00222 using namespace std; // For memcpy. 00223 00224 ::DCB dcb; 00225 memset(&dcb, 0, sizeof(DCB)); 00226 dcb.DCBlength = sizeof(DCB); 00227 if (!::GetCommState(handle_service_.native(impl), &dcb)) 00228 { 00229 DWORD last_error = ::GetLastError(); 00230 ec = asio::error_code(last_error, 00231 asio::error::get_system_category()); 00232 return ec; 00233 } 00234 00235 return option.load(dcb, ec); 00236 } 00237 00238 // Send a break sequence to the serial port. 00239 asio::error_code send_break(implementation_type& impl, 00240 asio::error_code& ec) 00241 { 00242 ec = asio::error::operation_not_supported; 00243 return ec; 00244 } 00245 00246 // Write the given data. Returns the number of bytes sent. 00247 template <typename ConstBufferSequence> 00248 size_t write_some(implementation_type& impl, 00249 const ConstBufferSequence& buffers, asio::error_code& ec) 00250 { 00251 return handle_service_.write_some(impl, buffers, ec); 00252 } 00253 00254 // Start an asynchronous write. The data being written must be valid for the 00255 // lifetime of the asynchronous operation. 00256 template <typename ConstBufferSequence, typename Handler> 00257 void async_write_some(implementation_type& impl, 00258 const ConstBufferSequence& buffers, Handler handler) 00259 { 00260 handle_service_.async_write_some(impl, buffers, handler); 00261 } 00262 00263 // Read some data. Returns the number of bytes received. 00264 template <typename MutableBufferSequence> 00265 size_t read_some(implementation_type& impl, 00266 const MutableBufferSequence& buffers, asio::error_code& ec) 00267 { 00268 return handle_service_.read_some(impl, buffers, ec); 00269 } 00270 00271 // Start an asynchronous read. The buffer for the data being received must be 00272 // valid for the lifetime of the asynchronous operation. 00273 template <typename MutableBufferSequence, typename Handler> 00274 void async_read_some(implementation_type& impl, 00275 const MutableBufferSequence& buffers, Handler handler) 00276 { 00277 handle_service_.async_read_some(impl, buffers, handler); 00278 } 00279 00280 private: 00281 // The handle service used for initiating asynchronous operations. 00282 win_iocp_handle_service& handle_service_; 00283 }; 00284 00285 } // namespace detail 00286 } // namespace asio 00287 00288 #endif // defined(ASIO_HAS_IOCP) 00289 00290 #include "asio/detail/pop_options.hpp" 00291 00292 #endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP