reactive_serial_port_service.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. //
  2. // reactive_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_REACTIVE_SERIAL_PORT_SERVICE_HPP
  12. #define ASIO_DETAIL_REACTIVE_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/serial_port_base.hpp"
  22. #if defined(ASIO_HAS_SERIAL_PORT) \
  23. && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  24. #include "asio/error.hpp"
  25. #include "asio/io_service.hpp"
  26. #include "asio/detail/descriptor_ops.hpp"
  27. #include "asio/detail/reactive_descriptor_service.hpp"
  28. namespace asio {
  29. namespace detail {
  30. // Extend reactive_descriptor_service to provide serial port support.
  31. class reactive_serial_port_service
  32. {
  33. public:
  34. // The native type of a serial port.
  35. typedef reactive_descriptor_service::native_type native_type;
  36. // The implementation type of the serial port.
  37. typedef reactive_descriptor_service::implementation_type implementation_type;
  38. reactive_serial_port_service(asio::io_service& io_service)
  39. : descriptor_service_(io_service)
  40. {
  41. }
  42. // Destroy all user-defined handler objects owned by the service.
  43. void shutdown_service()
  44. {
  45. descriptor_service_.shutdown_service();
  46. }
  47. // Construct a new handle implementation.
  48. void construct(implementation_type& impl)
  49. {
  50. descriptor_service_.construct(impl);
  51. }
  52. // Destroy a handle implementation.
  53. void destroy(implementation_type& impl)
  54. {
  55. descriptor_service_.destroy(impl);
  56. }
  57. // Open the serial port using the specified device name.
  58. asio::error_code open(implementation_type& impl,
  59. const std::string& device, asio::error_code& ec)
  60. {
  61. if (is_open(impl))
  62. {
  63. ec = asio::error::already_open;
  64. return ec;
  65. }
  66. int fd = descriptor_ops::open(device.c_str(),
  67. O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
  68. if (fd < 0)
  69. return ec;
  70. int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
  71. if (s >= 0)
  72. s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
  73. if (s < 0)
  74. {
  75. asio::error_code ignored_ec;
  76. descriptor_ops::close(fd, ignored_ec);
  77. return ec;
  78. }
  79. // Set up default serial port options.
  80. termios ios;
  81. descriptor_ops::clear_error(ec);
  82. s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
  83. if (s >= 0)
  84. {
  85. #if defined(_BSD_SOURCE)
  86. ::cfmakeraw(&ios);
  87. #else
  88. ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
  89. | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
  90. ios.c_oflag &= ~OPOST;
  91. ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  92. ios.c_cflag &= ~(CSIZE | PARENB);
  93. ios.c_cflag |= CS8;
  94. #endif
  95. ios.c_iflag |= IGNPAR;
  96. ios.c_cflag |= CREAD | CLOCAL;
  97. descriptor_ops::clear_error(ec);
  98. s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
  99. }
  100. if (s < 0)
  101. {
  102. asio::error_code ignored_ec;
  103. descriptor_ops::close(fd, ignored_ec);
  104. return ec;
  105. }
  106. // We're done. Take ownership of the serial port descriptor.
  107. if (descriptor_service_.assign(impl, fd, ec))
  108. {
  109. asio::error_code ignored_ec;
  110. descriptor_ops::close(fd, ignored_ec);
  111. }
  112. return ec;
  113. }
  114. // Assign a native handle to a handle implementation.
  115. asio::error_code assign(implementation_type& impl,
  116. const native_type& native_descriptor, asio::error_code& ec)
  117. {
  118. return descriptor_service_.assign(impl, native_descriptor, ec);
  119. }
  120. // Determine whether the handle is open.
  121. bool is_open(const implementation_type& impl) const
  122. {
  123. return descriptor_service_.is_open(impl);
  124. }
  125. // Destroy a handle implementation.
  126. asio::error_code close(implementation_type& impl,
  127. asio::error_code& ec)
  128. {
  129. return descriptor_service_.close(impl, ec);
  130. }
  131. // Get the native handle representation.
  132. native_type native(implementation_type& impl)
  133. {
  134. return descriptor_service_.native(impl);
  135. }
  136. // Cancel all operations associated with the handle.
  137. asio::error_code cancel(implementation_type& impl,
  138. asio::error_code& ec)
  139. {
  140. return descriptor_service_.cancel(impl, ec);
  141. }
  142. // Set an option on the serial port.
  143. template <typename SettableSerialPortOption>
  144. asio::error_code set_option(implementation_type& impl,
  145. const SettableSerialPortOption& option, asio::error_code& ec)
  146. {
  147. termios ios;
  148. descriptor_ops::clear_error(ec);
  149. descriptor_ops::error_wrapper(::tcgetattr(
  150. descriptor_service_.native(impl), &ios), ec);
  151. if (ec)
  152. return ec;
  153. if (option.store(ios, ec))
  154. return ec;
  155. descriptor_ops::clear_error(ec);
  156. descriptor_ops::error_wrapper(::tcsetattr(
  157. descriptor_service_.native(impl), TCSANOW, &ios), ec);
  158. return ec;
  159. }
  160. // Get an option from the serial port.
  161. template <typename GettableSerialPortOption>
  162. asio::error_code get_option(const implementation_type& impl,
  163. GettableSerialPortOption& option, asio::error_code& ec) const
  164. {
  165. termios ios;
  166. descriptor_ops::clear_error(ec);
  167. descriptor_ops::error_wrapper(::tcgetattr(
  168. descriptor_service_.native(impl), &ios), ec);
  169. if (ec)
  170. return ec;
  171. return option.load(ios, ec);
  172. }
  173. // Send a break sequence to the serial port.
  174. asio::error_code send_break(implementation_type& impl,
  175. asio::error_code& ec)
  176. {
  177. descriptor_ops::clear_error(ec);
  178. descriptor_ops::error_wrapper(::tcsendbreak(
  179. descriptor_service_.native(impl), 0), ec);
  180. return ec;
  181. }
  182. // Write the given data. Returns the number of bytes sent.
  183. template <typename ConstBufferSequence>
  184. size_t write_some(implementation_type& impl,
  185. const ConstBufferSequence& buffers, asio::error_code& ec)
  186. {
  187. return descriptor_service_.write_some(impl, buffers, ec);
  188. }
  189. // Start an asynchronous write. The data being written must be valid for the
  190. // lifetime of the asynchronous operation.
  191. template <typename ConstBufferSequence, typename Handler>
  192. void async_write_some(implementation_type& impl,
  193. const ConstBufferSequence& buffers, Handler handler)
  194. {
  195. descriptor_service_.async_write_some(impl, buffers, handler);
  196. }
  197. // Read some data. Returns the number of bytes received.
  198. template <typename MutableBufferSequence>
  199. size_t read_some(implementation_type& impl,
  200. const MutableBufferSequence& buffers, asio::error_code& ec)
  201. {
  202. return descriptor_service_.read_some(impl, buffers, ec);
  203. }
  204. // Start an asynchronous read. The buffer for the data being received must be
  205. // valid for the lifetime of the asynchronous operation.
  206. template <typename MutableBufferSequence, typename Handler>
  207. void async_read_some(implementation_type& impl,
  208. const MutableBufferSequence& buffers, Handler handler)
  209. {
  210. descriptor_service_.async_read_some(impl, buffers, handler);
  211. }
  212. private:
  213. // The implementation used for initiating asynchronous operations.
  214. reactive_descriptor_service descriptor_service_;
  215. };
  216. } // namespace detail
  217. } // namespace asio
  218. #endif // defined(ASIO_HAS_SERIAL_PORT)
  219. // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
  220. #include "asio/detail/pop_options.hpp"
  221. #endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP