2 // win_iocp_serial_port_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
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)
12 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
13 #define BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
15 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
19 #include <boost/asio/detail/push_options.hpp>
21 #include <boost/asio/detail/push_options.hpp>
24 #include <boost/asio/detail/pop_options.hpp>
26 #include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
28 #if defined(BOOST_ASIO_HAS_IOCP)
30 #include <boost/asio/error.hpp>
31 #include <boost/asio/io_service.hpp>
32 #include <boost/asio/detail/win_iocp_handle_service.hpp>
38 // Extend win_iocp_handle_service to provide serial port support.
39 class win_iocp_serial_port_service
40 : public boost::asio::detail::service_base
<win_iocp_serial_port_service
>
43 // The native type of a stream handle.
44 typedef win_iocp_handle_service::native_type native_type
;
46 // The implementation type of the stream handle.
47 typedef win_iocp_handle_service::implementation_type implementation_type
;
49 win_iocp_serial_port_service(boost::asio::io_service
& io_service
)
50 : boost::asio::detail::service_base
<
51 win_iocp_serial_port_service
>(io_service
),
53 boost::asio::use_service
<win_iocp_handle_service
>(io_service
))
57 // Destroy all user-defined handler objects owned by the service.
58 void shutdown_service()
62 // Construct a new handle implementation.
63 void construct(implementation_type
& impl
)
65 handle_service_
.construct(impl
);
68 // Destroy a handle implementation.
69 void destroy(implementation_type
& impl
)
71 handle_service_
.destroy(impl
);
74 // Open the serial port using the specified device name.
75 boost::system::error_code
open(implementation_type
& impl
,
76 const std::string
& device
, boost::system::error_code
& ec
)
80 ec
= boost::asio::error::already_open
;
84 // For convenience, add a leading \\.\ sequence if not already present.
85 std::string name
= (device
[0] == '\\') ? device
: "\\\\.\\" + device
;
87 // Open a handle to the serial port.
88 ::HANDLE handle
= ::CreateFileA(name
.c_str(),
89 GENERIC_READ
| GENERIC_WRITE
, 0, 0,
90 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, 0);
91 if (handle
== INVALID_HANDLE_VALUE
)
93 DWORD last_error
= ::GetLastError();
94 ec
= boost::system::error_code(last_error
,
95 boost::asio::error::get_system_category());
99 // Determine the initial serial port parameters.
100 using namespace std
; // For memcpy.
102 memset(&dcb
, 0, sizeof(DCB
));
103 dcb
.DCBlength
= sizeof(DCB
);
104 if (!::GetCommState(handle
, &dcb
))
106 DWORD last_error
= ::GetLastError();
107 ::CloseHandle(handle
);
108 ec
= boost::system::error_code(last_error
,
109 boost::asio::error::get_system_category());
113 // Set some default serial port parameters. This implementation does not
114 // support changing these, so they might as well be in a known state.
115 dcb
.fBinary
= TRUE
; // Win32 only supports binary mode.
116 dcb
.fDsrSensitivity
= FALSE
;
117 dcb
.fNull
= FALSE
; // Do not ignore NULL characters.
118 dcb
.fAbortOnError
= FALSE
; // Ignore serial framing errors.
119 if (!::SetCommState(handle
, &dcb
))
121 DWORD last_error
= ::GetLastError();
122 ::CloseHandle(handle
);
123 ec
= boost::system::error_code(last_error
,
124 boost::asio::error::get_system_category());
128 // Set up timeouts so that the serial port will behave similarly to a
129 // network socket. Reads wait for at least one byte, then return with
130 // whatever they have. Writes return once everything is out the door.
131 ::COMMTIMEOUTS timeouts
;
132 timeouts
.ReadIntervalTimeout
= 1;
133 timeouts
.ReadTotalTimeoutMultiplier
= 0;
134 timeouts
.ReadTotalTimeoutConstant
= 0;
135 timeouts
.WriteTotalTimeoutMultiplier
= 0;
136 timeouts
.WriteTotalTimeoutConstant
= 0;
137 if (!::SetCommTimeouts(handle
, &timeouts
))
139 DWORD last_error
= ::GetLastError();
140 ::CloseHandle(handle
);
141 ec
= boost::system::error_code(last_error
,
142 boost::asio::error::get_system_category());
146 // We're done. Take ownership of the serial port handle.
147 if (handle_service_
.assign(impl
, handle
, ec
))
148 ::CloseHandle(handle
);
152 // Assign a native handle to a handle implementation.
153 boost::system::error_code
assign(implementation_type
& impl
,
154 const native_type
& native_handle
, boost::system::error_code
& ec
)
156 return handle_service_
.assign(impl
, native_handle
, ec
);
159 // Determine whether the handle is open.
160 bool is_open(const implementation_type
& impl
) const
162 return handle_service_
.is_open(impl
);
165 // Destroy a handle implementation.
166 boost::system::error_code
close(implementation_type
& impl
,
167 boost::system::error_code
& ec
)
169 return handle_service_
.close(impl
, ec
);
172 // Get the native handle representation.
173 native_type
native(implementation_type
& impl
)
175 return handle_service_
.native(impl
);
178 // Cancel all operations associated with the handle.
179 boost::system::error_code
cancel(implementation_type
& impl
,
180 boost::system::error_code
& ec
)
182 return handle_service_
.cancel(impl
, ec
);
185 // Set an option on the serial port.
186 template <typename SettableSerialPortOption
>
187 boost::system::error_code
set_option(implementation_type
& impl
,
188 const SettableSerialPortOption
& option
, boost::system::error_code
& ec
)
190 using namespace std
; // For memcpy.
193 memset(&dcb
, 0, sizeof(DCB
));
194 dcb
.DCBlength
= sizeof(DCB
);
195 if (!::GetCommState(handle_service_
.native(impl
), &dcb
))
197 DWORD last_error
= ::GetLastError();
198 ec
= boost::system::error_code(last_error
,
199 boost::asio::error::get_system_category());
203 if (option
.store(dcb
, ec
))
206 if (!::SetCommState(handle_service_
.native(impl
), &dcb
))
208 DWORD last_error
= ::GetLastError();
209 ec
= boost::system::error_code(last_error
,
210 boost::asio::error::get_system_category());
214 ec
= boost::system::error_code();
218 // Get an option from the serial port.
219 template <typename GettableSerialPortOption
>
220 boost::system::error_code
get_option(const implementation_type
& impl
,
221 GettableSerialPortOption
& option
, boost::system::error_code
& ec
) const
223 using namespace std
; // For memcpy.
226 memset(&dcb
, 0, sizeof(DCB
));
227 dcb
.DCBlength
= sizeof(DCB
);
228 if (!::GetCommState(handle_service_
.native(impl
), &dcb
))
230 DWORD last_error
= ::GetLastError();
231 ec
= boost::system::error_code(last_error
,
232 boost::asio::error::get_system_category());
236 return option
.load(dcb
, ec
);
239 // Send a break sequence to the serial port.
240 boost::system::error_code
send_break(implementation_type
&,
241 boost::system::error_code
& ec
)
243 ec
= boost::asio::error::operation_not_supported
;
247 // Write the given data. Returns the number of bytes sent.
248 template <typename ConstBufferSequence
>
249 size_t write_some(implementation_type
& impl
,
250 const ConstBufferSequence
& buffers
, boost::system::error_code
& ec
)
252 return handle_service_
.write_some(impl
, buffers
, ec
);
255 // Start an asynchronous write. The data being written must be valid for the
256 // lifetime of the asynchronous operation.
257 template <typename ConstBufferSequence
, typename Handler
>
258 void async_write_some(implementation_type
& impl
,
259 const ConstBufferSequence
& buffers
, Handler handler
)
261 handle_service_
.async_write_some(impl
, buffers
, handler
);
264 // Read some data. Returns the number of bytes received.
265 template <typename MutableBufferSequence
>
266 size_t read_some(implementation_type
& impl
,
267 const MutableBufferSequence
& buffers
, boost::system::error_code
& ec
)
269 return handle_service_
.read_some(impl
, buffers
, ec
);
272 // Start an asynchronous read. The buffer for the data being received must be
273 // valid for the lifetime of the asynchronous operation.
274 template <typename MutableBufferSequence
, typename Handler
>
275 void async_read_some(implementation_type
& impl
,
276 const MutableBufferSequence
& buffers
, Handler handler
)
278 handle_service_
.async_read_some(impl
, buffers
, handler
);
282 // The handle service used for initiating asynchronous operations.
283 win_iocp_handle_service
& handle_service_
;
286 } // namespace detail
290 #endif // defined(BOOST_ASIO_HAS_IOCP)
292 #include <boost/asio/detail/pop_options.hpp>
294 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP