win_iocp_serial_port_service.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. //
  2. // win_iocp_serial_port_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2010 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. #ifndef ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
  12. #define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include "asio/detail/push_options.hpp"
  17. #include "asio/detail/push_options.hpp"
  18. #include <cstring>
  19. #include <string>
  20. #include "asio/detail/pop_options.hpp"
  21. #include "asio/detail/win_iocp_io_service_fwd.hpp"
  22. #if defined(ASIO_HAS_IOCP)
  23. #include "asio/error.hpp"
  24. #include "asio/io_service.hpp"
  25. #include "asio/detail/win_iocp_handle_service.hpp"
  26. namespace asio {
  27. namespace detail {
  28. // Extend win_iocp_handle_service to provide serial port support.
  29. class win_iocp_serial_port_service
  30. {
  31. public:
  32. // The native type of a stream handle.
  33. typedef win_iocp_handle_service::native_type native_type;
  34. // The implementation type of the stream handle.
  35. typedef win_iocp_handle_service::implementation_type implementation_type;
  36. win_iocp_serial_port_service(asio::io_service& io_service)
  37. : handle_service_(io_service)
  38. {
  39. }
  40. // Destroy all user-defined handler objects owned by the service.
  41. void shutdown_service()
  42. {
  43. }
  44. // Construct a new handle implementation.
  45. void construct(implementation_type& impl)
  46. {
  47. handle_service_.construct(impl);
  48. }
  49. // Destroy a handle implementation.
  50. void destroy(implementation_type& impl)
  51. {
  52. handle_service_.destroy(impl);
  53. }
  54. // Open the serial port using the specified device name.
  55. asio::error_code open(implementation_type& impl,
  56. const std::string& device, asio::error_code& ec)
  57. {
  58. if (is_open(impl))
  59. {
  60. ec = asio::error::already_open;
  61. return ec;
  62. }
  63. // For convenience, add a leading \\.\ sequence if not already present.
  64. std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
  65. // Open a handle to the serial port.
  66. ::HANDLE handle = ::CreateFileA(name.c_str(),
  67. GENERIC_READ | GENERIC_WRITE, 0, 0,
  68. OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  69. if (handle == INVALID_HANDLE_VALUE)
  70. {
  71. DWORD last_error = ::GetLastError();
  72. ec = asio::error_code(last_error,
  73. asio::error::get_system_category());
  74. return ec;
  75. }
  76. // Determine the initial serial port parameters.
  77. using namespace std; // For memcpy.
  78. ::DCB dcb;
  79. memset(&dcb, 0, sizeof(DCB));
  80. dcb.DCBlength = sizeof(DCB);
  81. if (!::GetCommState(handle, &dcb))
  82. {
  83. DWORD last_error = ::GetLastError();
  84. ::CloseHandle(handle);
  85. ec = asio::error_code(last_error,
  86. asio::error::get_system_category());
  87. return ec;
  88. }
  89. // Set some default serial port parameters. This implementation does not
  90. // support changing these, so they might as well be in a known state.
  91. dcb.fBinary = TRUE; // Win32 only supports binary mode.
  92. dcb.fDsrSensitivity = FALSE;
  93. dcb.fNull = FALSE; // Do not ignore NULL characters.
  94. dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
  95. if (!::SetCommState(handle, &dcb))
  96. {
  97. DWORD last_error = ::GetLastError();
  98. ::CloseHandle(handle);
  99. ec = asio::error_code(last_error,
  100. asio::error::get_system_category());
  101. return ec;
  102. }
  103. // Set up timeouts so that the serial port will behave similarly to a
  104. // network socket. Reads wait for at least one byte, then return with
  105. // whatever they have. Writes return once everything is out the door.
  106. ::COMMTIMEOUTS timeouts;
  107. timeouts.ReadIntervalTimeout = 1;
  108. timeouts.ReadTotalTimeoutMultiplier = 0;
  109. timeouts.ReadTotalTimeoutConstant = 0;
  110. timeouts.WriteTotalTimeoutMultiplier = 0;
  111. timeouts.WriteTotalTimeoutConstant = 0;
  112. if (!::SetCommTimeouts(handle, &timeouts))
  113. {
  114. DWORD last_error = ::GetLastError();
  115. ::CloseHandle(handle);
  116. ec = asio::error_code(last_error,
  117. asio::error::get_system_category());
  118. return ec;
  119. }
  120. // We're done. Take ownership of the serial port handle.
  121. if (handle_service_.assign(impl, handle, ec))
  122. ::CloseHandle(handle);
  123. return ec;
  124. }
  125. // Assign a native handle to a handle implementation.
  126. asio::error_code assign(implementation_type& impl,
  127. const native_type& native_handle, asio::error_code& ec)
  128. {
  129. return handle_service_.assign(impl, native_handle, ec);
  130. }
  131. // Determine whether the handle is open.
  132. bool is_open(const implementation_type& impl) const
  133. {
  134. return handle_service_.is_open(impl);
  135. }
  136. // Destroy a handle implementation.
  137. asio::error_code close(implementation_type& impl,
  138. asio::error_code& ec)
  139. {
  140. return handle_service_.close(impl, ec);
  141. }
  142. // Get the native handle representation.
  143. native_type native(implementation_type& impl)
  144. {
  145. return handle_service_.native(impl);
  146. }
  147. // Cancel all operations associated with the handle.
  148. asio::error_code cancel(implementation_type& impl,
  149. asio::error_code& ec)
  150. {
  151. return handle_service_.cancel(impl, ec);
  152. }
  153. // Set an option on the serial port.
  154. template <typename SettableSerialPortOption>
  155. asio::error_code set_option(implementation_type& impl,
  156. const SettableSerialPortOption& option, asio::error_code& ec)
  157. {
  158. using namespace std; // For memcpy.
  159. ::DCB dcb;
  160. memset(&dcb, 0, sizeof(DCB));
  161. dcb.DCBlength = sizeof(DCB);
  162. if (!::GetCommState(handle_service_.native(impl), &dcb))
  163. {
  164. DWORD last_error = ::GetLastError();
  165. ec = asio::error_code(last_error,
  166. asio::error::get_system_category());
  167. return ec;
  168. }
  169. if (option.store(dcb, ec))
  170. return ec;
  171. if (!::SetCommState(handle_service_.native(impl), &dcb))
  172. {
  173. DWORD last_error = ::GetLastError();
  174. ec = asio::error_code(last_error,
  175. asio::error::get_system_category());
  176. return ec;
  177. }
  178. ec = asio::error_code();
  179. return ec;
  180. }
  181. // Get an option from the serial port.
  182. template <typename GettableSerialPortOption>
  183. asio::error_code get_option(const implementation_type& impl,
  184. GettableSerialPortOption& option, asio::error_code& ec) const
  185. {
  186. using namespace std; // For memcpy.
  187. ::DCB dcb;
  188. memset(&dcb, 0, sizeof(DCB));
  189. dcb.DCBlength = sizeof(DCB);
  190. if (!::GetCommState(handle_service_.native(impl), &dcb))
  191. {
  192. DWORD last_error = ::GetLastError();
  193. ec = asio::error_code(last_error,
  194. asio::error::get_system_category());
  195. return ec;
  196. }
  197. return option.load(dcb, ec);
  198. }
  199. // Send a break sequence to the serial port.
  200. asio::error_code send_break(implementation_type&,
  201. asio::error_code& ec)
  202. {
  203. ec = asio::error::operation_not_supported;
  204. return ec;
  205. }
  206. // Write the given data. Returns the number of bytes sent.
  207. template <typename ConstBufferSequence>
  208. size_t write_some(implementation_type& impl,
  209. const ConstBufferSequence& buffers, asio::error_code& ec)
  210. {
  211. return handle_service_.write_some(impl, buffers, ec);
  212. }
  213. // Start an asynchronous write. The data being written must be valid for the
  214. // lifetime of the asynchronous operation.
  215. template <typename ConstBufferSequence, typename Handler>
  216. void async_write_some(implementation_type& impl,
  217. const ConstBufferSequence& buffers, Handler handler)
  218. {
  219. handle_service_.async_write_some(impl, buffers, handler);
  220. }
  221. // Read some data. Returns the number of bytes received.
  222. template <typename MutableBufferSequence>
  223. size_t read_some(implementation_type& impl,
  224. const MutableBufferSequence& buffers, asio::error_code& ec)
  225. {
  226. return handle_service_.read_some(impl, buffers, ec);
  227. }
  228. // Start an asynchronous read. The buffer for the data being received must be
  229. // valid for the lifetime of the asynchronous operation.
  230. template <typename MutableBufferSequence, typename Handler>
  231. void async_read_some(implementation_type& impl,
  232. const MutableBufferSequence& buffers, Handler handler)
  233. {
  234. handle_service_.async_read_some(impl, buffers, handler);
  235. }
  236. private:
  237. // The implementation used for initiating asynchronous operations.
  238. win_iocp_handle_service handle_service_;
  239. };
  240. } // namespace detail
  241. } // namespace asio
  242. #endif // defined(ASIO_HAS_IOCP)
  243. #include "asio/detail/pop_options.hpp"
  244. #endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP