win_iocp_serial_port_service.ipp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. //
  2. // detail/impl/win_iocp_serial_port_service.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
  12. #define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include "asio/detail/config.hpp"
  17. #if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
  18. #include <cstring>
  19. #include "asio/detail/win_iocp_serial_port_service.hpp"
  20. #include "asio/detail/push_options.hpp"
  21. namespace asio {
  22. namespace detail {
  23. win_iocp_serial_port_service::win_iocp_serial_port_service(
  24. execution_context& context)
  25. : execution_context_service_base<win_iocp_serial_port_service>(context),
  26. handle_service_(context)
  27. {
  28. }
  29. void win_iocp_serial_port_service::shutdown()
  30. {
  31. }
  32. asio::error_code win_iocp_serial_port_service::open(
  33. win_iocp_serial_port_service::implementation_type& impl,
  34. const std::string& device, asio::error_code& ec)
  35. {
  36. if (is_open(impl))
  37. {
  38. ec = asio::error::already_open;
  39. ASIO_ERROR_LOCATION(ec);
  40. return ec;
  41. }
  42. // For convenience, add a leading \\.\ sequence if not already present.
  43. std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
  44. // Open a handle to the serial port.
  45. ::HANDLE handle = ::CreateFileA(name.c_str(),
  46. GENERIC_READ | GENERIC_WRITE, 0, 0,
  47. OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  48. if (handle == INVALID_HANDLE_VALUE)
  49. {
  50. DWORD last_error = ::GetLastError();
  51. ec = asio::error_code(last_error,
  52. asio::error::get_system_category());
  53. ASIO_ERROR_LOCATION(ec);
  54. return ec;
  55. }
  56. // Determine the initial serial port parameters.
  57. using namespace std; // For memset.
  58. ::DCB dcb;
  59. memset(&dcb, 0, sizeof(DCB));
  60. dcb.DCBlength = sizeof(DCB);
  61. if (!::GetCommState(handle, &dcb))
  62. {
  63. DWORD last_error = ::GetLastError();
  64. ::CloseHandle(handle);
  65. ec = asio::error_code(last_error,
  66. asio::error::get_system_category());
  67. ASIO_ERROR_LOCATION(ec);
  68. return ec;
  69. }
  70. // Set some default serial port parameters. This implementation does not
  71. // support changing all of these, so they might as well be in a known state.
  72. dcb.fBinary = TRUE; // Win32 only supports binary mode.
  73. dcb.fNull = FALSE; // Do not ignore NULL characters.
  74. dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
  75. dcb.BaudRate = CBR_9600; // 9600 baud by default
  76. dcb.ByteSize = 8; // 8 bit bytes
  77. dcb.fOutxCtsFlow = FALSE; // No flow control
  78. dcb.fOutxDsrFlow = FALSE;
  79. dcb.fDtrControl = DTR_CONTROL_DISABLE;
  80. dcb.fDsrSensitivity = FALSE;
  81. dcb.fOutX = FALSE;
  82. dcb.fInX = FALSE;
  83. dcb.fRtsControl = RTS_CONTROL_DISABLE;
  84. dcb.fParity = FALSE; // No parity
  85. dcb.Parity = NOPARITY;
  86. dcb.StopBits = ONESTOPBIT; // One stop bit
  87. if (!::SetCommState(handle, &dcb))
  88. {
  89. DWORD last_error = ::GetLastError();
  90. ::CloseHandle(handle);
  91. ec = asio::error_code(last_error,
  92. asio::error::get_system_category());
  93. ASIO_ERROR_LOCATION(ec);
  94. return ec;
  95. }
  96. // Set up timeouts so that the serial port will behave similarly to a
  97. // network socket. Reads wait for at least one byte, then return with
  98. // whatever they have. Writes return once everything is out the door.
  99. ::COMMTIMEOUTS timeouts;
  100. timeouts.ReadIntervalTimeout = 1;
  101. timeouts.ReadTotalTimeoutMultiplier = 0;
  102. timeouts.ReadTotalTimeoutConstant = 0;
  103. timeouts.WriteTotalTimeoutMultiplier = 0;
  104. timeouts.WriteTotalTimeoutConstant = 0;
  105. if (!::SetCommTimeouts(handle, &timeouts))
  106. {
  107. DWORD last_error = ::GetLastError();
  108. ::CloseHandle(handle);
  109. ec = asio::error_code(last_error,
  110. asio::error::get_system_category());
  111. ASIO_ERROR_LOCATION(ec);
  112. return ec;
  113. }
  114. // We're done. Take ownership of the serial port handle.
  115. if (handle_service_.assign(impl, handle, ec))
  116. ::CloseHandle(handle);
  117. return ec;
  118. }
  119. asio::error_code win_iocp_serial_port_service::do_set_option(
  120. win_iocp_serial_port_service::implementation_type& impl,
  121. win_iocp_serial_port_service::store_function_type store,
  122. const void* option, asio::error_code& ec)
  123. {
  124. using namespace std; // For memcpy.
  125. ::DCB dcb;
  126. memset(&dcb, 0, sizeof(DCB));
  127. dcb.DCBlength = sizeof(DCB);
  128. if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
  129. {
  130. DWORD last_error = ::GetLastError();
  131. ec = asio::error_code(last_error,
  132. asio::error::get_system_category());
  133. ASIO_ERROR_LOCATION(ec);
  134. return ec;
  135. }
  136. if (store(option, dcb, ec))
  137. return ec;
  138. if (!::SetCommState(handle_service_.native_handle(impl), &dcb))
  139. {
  140. DWORD last_error = ::GetLastError();
  141. ec = asio::error_code(last_error,
  142. asio::error::get_system_category());
  143. ASIO_ERROR_LOCATION(ec);
  144. return ec;
  145. }
  146. ec = asio::error_code();
  147. return ec;
  148. }
  149. asio::error_code win_iocp_serial_port_service::do_get_option(
  150. const win_iocp_serial_port_service::implementation_type& impl,
  151. win_iocp_serial_port_service::load_function_type load,
  152. void* option, asio::error_code& ec) const
  153. {
  154. using namespace std; // For memset.
  155. ::DCB dcb;
  156. memset(&dcb, 0, sizeof(DCB));
  157. dcb.DCBlength = sizeof(DCB);
  158. if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
  159. {
  160. DWORD last_error = ::GetLastError();
  161. ec = asio::error_code(last_error,
  162. asio::error::get_system_category());
  163. ASIO_ERROR_LOCATION(ec);
  164. return ec;
  165. }
  166. return load(option, dcb, ec);
  167. }
  168. } // namespace detail
  169. } // namespace asio
  170. #include "asio/detail/pop_options.hpp"
  171. #endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
  172. #endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP