1 | // |
2 | // basic_serial_port.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 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 | |
12 | #ifndef BOOST_ASIO_BASIC_SERIAL_PORT_HPP |
13 | #define BOOST_ASIO_BASIC_SERIAL_PORT_HPP |
14 | |
15 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
16 | # pragma once |
17 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
18 | |
19 | #include <boost/asio/detail/config.hpp> |
20 | |
21 | #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ |
22 | || defined(GENERATING_DOCUMENTATION) |
23 | |
24 | #include <string> |
25 | #include <utility> |
26 | #include <boost/asio/any_io_executor.hpp> |
27 | #include <boost/asio/async_result.hpp> |
28 | #include <boost/asio/detail/handler_type_requirements.hpp> |
29 | #include <boost/asio/detail/io_object_impl.hpp> |
30 | #include <boost/asio/detail/non_const_lvalue.hpp> |
31 | #include <boost/asio/detail/throw_error.hpp> |
32 | #include <boost/asio/detail/type_traits.hpp> |
33 | #include <boost/asio/error.hpp> |
34 | #include <boost/asio/execution_context.hpp> |
35 | #include <boost/asio/serial_port_base.hpp> |
36 | #if defined(BOOST_ASIO_HAS_IOCP) |
37 | # include <boost/asio/detail/win_iocp_serial_port_service.hpp> |
38 | #else |
39 | # include <boost/asio/detail/posix_serial_port_service.hpp> |
40 | #endif |
41 | |
42 | #include <boost/asio/detail/push_options.hpp> |
43 | |
44 | namespace boost { |
45 | namespace asio { |
46 | |
47 | /// Provides serial port functionality. |
48 | /** |
49 | * The basic_serial_port class provides a wrapper over serial port |
50 | * functionality. |
51 | * |
52 | * @par Thread Safety |
53 | * @e Distinct @e objects: Safe.@n |
54 | * @e Shared @e objects: Unsafe. |
55 | */ |
56 | template <typename Executor = any_io_executor> |
57 | class basic_serial_port |
58 | : public serial_port_base |
59 | { |
60 | private: |
61 | class initiate_async_write_some; |
62 | class initiate_async_read_some; |
63 | |
64 | public: |
65 | /// The type of the executor associated with the object. |
66 | typedef Executor executor_type; |
67 | |
68 | /// Rebinds the serial port type to another executor. |
69 | template <typename Executor1> |
70 | struct rebind_executor |
71 | { |
72 | /// The serial port type when rebound to the specified executor. |
73 | typedef basic_serial_port<Executor1> other; |
74 | }; |
75 | |
76 | /// The native representation of a serial port. |
77 | #if defined(GENERATING_DOCUMENTATION) |
78 | typedef implementation_defined native_handle_type; |
79 | #elif defined(BOOST_ASIO_HAS_IOCP) |
80 | typedef detail::win_iocp_serial_port_service::native_handle_type |
81 | native_handle_type; |
82 | #else |
83 | typedef detail::posix_serial_port_service::native_handle_type |
84 | native_handle_type; |
85 | #endif |
86 | |
87 | /// A basic_basic_serial_port is always the lowest layer. |
88 | typedef basic_serial_port lowest_layer_type; |
89 | |
90 | /// Construct a basic_serial_port without opening it. |
91 | /** |
92 | * This constructor creates a serial port without opening it. |
93 | * |
94 | * @param ex The I/O executor that the serial port will use, by default, to |
95 | * dispatch handlers for any asynchronous operations performed on the |
96 | * serial port. |
97 | */ |
98 | explicit basic_serial_port(const executor_type& ex) |
99 | : impl_(0, ex) |
100 | { |
101 | } |
102 | |
103 | /// Construct a basic_serial_port without opening it. |
104 | /** |
105 | * This constructor creates a serial port without opening it. |
106 | * |
107 | * @param context An execution context which provides the I/O executor that |
108 | * the serial port will use, by default, to dispatch handlers for any |
109 | * asynchronous operations performed on the serial port. |
110 | */ |
111 | template <typename ExecutionContext> |
112 | explicit basic_serial_port(ExecutionContext& context, |
113 | constraint_t< |
114 | is_convertible<ExecutionContext&, execution_context&>::value, |
115 | defaulted_constraint |
116 | > = defaulted_constraint()) |
117 | : impl_(0, 0, context) |
118 | { |
119 | } |
120 | |
121 | /// Construct and open a basic_serial_port. |
122 | /** |
123 | * This constructor creates and opens a serial port for the specified device |
124 | * name. |
125 | * |
126 | * @param ex The I/O executor that the serial port will use, by default, to |
127 | * dispatch handlers for any asynchronous operations performed on the |
128 | * serial port. |
129 | * |
130 | * @param device The platform-specific device name for this serial |
131 | * port. |
132 | */ |
133 | basic_serial_port(const executor_type& ex, const char* device) |
134 | : impl_(0, ex) |
135 | { |
136 | boost::system::error_code ec; |
137 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
138 | boost::asio::detail::throw_error(err: ec, location: "open" ); |
139 | } |
140 | |
141 | /// Construct and open a basic_serial_port. |
142 | /** |
143 | * This constructor creates and opens a serial port for the specified device |
144 | * name. |
145 | * |
146 | * @param context An execution context which provides the I/O executor that |
147 | * the serial port will use, by default, to dispatch handlers for any |
148 | * asynchronous operations performed on the serial port. |
149 | * |
150 | * @param device The platform-specific device name for this serial |
151 | * port. |
152 | */ |
153 | template <typename ExecutionContext> |
154 | basic_serial_port(ExecutionContext& context, const char* device, |
155 | constraint_t< |
156 | is_convertible<ExecutionContext&, execution_context&>::value |
157 | > = 0) |
158 | : impl_(0, 0, context) |
159 | { |
160 | boost::system::error_code ec; |
161 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
162 | boost::asio::detail::throw_error(err: ec, location: "open" ); |
163 | } |
164 | |
165 | /// Construct and open a basic_serial_port. |
166 | /** |
167 | * This constructor creates and opens a serial port for the specified device |
168 | * name. |
169 | * |
170 | * @param ex The I/O executor that the serial port will use, by default, to |
171 | * dispatch handlers for any asynchronous operations performed on the |
172 | * serial port. |
173 | * |
174 | * @param device The platform-specific device name for this serial |
175 | * port. |
176 | */ |
177 | basic_serial_port(const executor_type& ex, const std::string& device) |
178 | : impl_(0, ex) |
179 | { |
180 | boost::system::error_code ec; |
181 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
182 | boost::asio::detail::throw_error(err: ec, location: "open" ); |
183 | } |
184 | |
185 | /// Construct and open a basic_serial_port. |
186 | /** |
187 | * This constructor creates and opens a serial port for the specified device |
188 | * name. |
189 | * |
190 | * @param context An execution context which provides the I/O executor that |
191 | * the serial port will use, by default, to dispatch handlers for any |
192 | * asynchronous operations performed on the serial port. |
193 | * |
194 | * @param device The platform-specific device name for this serial |
195 | * port. |
196 | */ |
197 | template <typename ExecutionContext> |
198 | basic_serial_port(ExecutionContext& context, const std::string& device, |
199 | constraint_t< |
200 | is_convertible<ExecutionContext&, execution_context&>::value |
201 | > = 0) |
202 | : impl_(0, 0, context) |
203 | { |
204 | boost::system::error_code ec; |
205 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
206 | boost::asio::detail::throw_error(err: ec, location: "open" ); |
207 | } |
208 | |
209 | /// Construct a basic_serial_port on an existing native serial port. |
210 | /** |
211 | * This constructor creates a serial port object to hold an existing native |
212 | * serial port. |
213 | * |
214 | * @param ex The I/O executor that the serial port will use, by default, to |
215 | * dispatch handlers for any asynchronous operations performed on the |
216 | * serial port. |
217 | * |
218 | * @param native_serial_port A native serial port. |
219 | * |
220 | * @throws boost::system::system_error Thrown on failure. |
221 | */ |
222 | basic_serial_port(const executor_type& ex, |
223 | const native_handle_type& native_serial_port) |
224 | : impl_(0, ex) |
225 | { |
226 | boost::system::error_code ec; |
227 | impl_.get_service().assign(impl_.get_implementation(), |
228 | native_serial_port, ec); |
229 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
230 | } |
231 | |
232 | /// Construct a basic_serial_port on an existing native serial port. |
233 | /** |
234 | * This constructor creates a serial port object to hold an existing native |
235 | * serial port. |
236 | * |
237 | * @param context An execution context which provides the I/O executor that |
238 | * the serial port will use, by default, to dispatch handlers for any |
239 | * asynchronous operations performed on the serial port. |
240 | * |
241 | * @param native_serial_port A native serial port. |
242 | * |
243 | * @throws boost::system::system_error Thrown on failure. |
244 | */ |
245 | template <typename ExecutionContext> |
246 | basic_serial_port(ExecutionContext& context, |
247 | const native_handle_type& native_serial_port, |
248 | constraint_t< |
249 | is_convertible<ExecutionContext&, execution_context&>::value |
250 | > = 0) |
251 | : impl_(0, 0, context) |
252 | { |
253 | boost::system::error_code ec; |
254 | impl_.get_service().assign(impl_.get_implementation(), |
255 | native_serial_port, ec); |
256 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
257 | } |
258 | |
259 | /// Move-construct a basic_serial_port from another. |
260 | /** |
261 | * This constructor moves a serial port from one object to another. |
262 | * |
263 | * @param other The other basic_serial_port object from which the move will |
264 | * occur. |
265 | * |
266 | * @note Following the move, the moved-from object is in the same state as if |
267 | * constructed using the @c basic_serial_port(const executor_type&) |
268 | * constructor. |
269 | */ |
270 | basic_serial_port(basic_serial_port&& other) |
271 | : impl_(std::move(other.impl_)) |
272 | { |
273 | } |
274 | |
275 | /// Move-assign a basic_serial_port from another. |
276 | /** |
277 | * This assignment operator moves a serial port from one object to another. |
278 | * |
279 | * @param other The other basic_serial_port object from which the move will |
280 | * occur. |
281 | * |
282 | * @note Following the move, the moved-from object is in the same state as if |
283 | * constructed using the @c basic_serial_port(const executor_type&) |
284 | * constructor. |
285 | */ |
286 | basic_serial_port& operator=(basic_serial_port&& other) |
287 | { |
288 | impl_ = std::move(other.impl_); |
289 | return *this; |
290 | } |
291 | |
292 | // All serial ports have access to each other's implementations. |
293 | template <typename Executor1> |
294 | friend class basic_serial_port; |
295 | |
296 | /// Move-construct a basic_serial_port from a serial port of another executor |
297 | /// type. |
298 | /** |
299 | * This constructor moves a serial port from one object to another. |
300 | * |
301 | * @param other The other basic_serial_port object from which the move will |
302 | * occur. |
303 | * |
304 | * @note Following the move, the moved-from object is in the same state as if |
305 | * constructed using the @c basic_serial_port(const executor_type&) |
306 | * constructor. |
307 | */ |
308 | template <typename Executor1> |
309 | basic_serial_port(basic_serial_port<Executor1>&& other, |
310 | constraint_t< |
311 | is_convertible<Executor1, Executor>::value, |
312 | defaulted_constraint |
313 | > = defaulted_constraint()) |
314 | : impl_(std::move(other.impl_)) |
315 | { |
316 | } |
317 | |
318 | /// Move-assign a basic_serial_port from a serial port of another executor |
319 | /// type. |
320 | /** |
321 | * This assignment operator moves a serial port from one object to another. |
322 | * |
323 | * @param other The other basic_serial_port object from which the move will |
324 | * occur. |
325 | * |
326 | * @note Following the move, the moved-from object is in the same state as if |
327 | * constructed using the @c basic_serial_port(const executor_type&) |
328 | * constructor. |
329 | */ |
330 | template <typename Executor1> |
331 | constraint_t< |
332 | is_convertible<Executor1, Executor>::value, |
333 | basic_serial_port& |
334 | > operator=(basic_serial_port<Executor1>&& other) |
335 | { |
336 | basic_serial_port tmp(std::move(other)); |
337 | impl_ = std::move(tmp.impl_); |
338 | return *this; |
339 | } |
340 | |
341 | /// Destroys the serial port. |
342 | /** |
343 | * This function destroys the serial port, cancelling any outstanding |
344 | * asynchronous wait operations associated with the serial port as if by |
345 | * calling @c cancel. |
346 | */ |
347 | ~basic_serial_port() |
348 | { |
349 | } |
350 | |
351 | /// Get the executor associated with the object. |
352 | const executor_type& get_executor() noexcept |
353 | { |
354 | return impl_.get_executor(); |
355 | } |
356 | |
357 | /// Get a reference to the lowest layer. |
358 | /** |
359 | * This function returns a reference to the lowest layer in a stack of |
360 | * layers. Since a basic_serial_port cannot contain any further layers, it |
361 | * simply returns a reference to itself. |
362 | * |
363 | * @return A reference to the lowest layer in the stack of layers. Ownership |
364 | * is not transferred to the caller. |
365 | */ |
366 | lowest_layer_type& lowest_layer() |
367 | { |
368 | return *this; |
369 | } |
370 | |
371 | /// Get a const reference to the lowest layer. |
372 | /** |
373 | * This function returns a const reference to the lowest layer in a stack of |
374 | * layers. Since a basic_serial_port cannot contain any further layers, it |
375 | * simply returns a reference to itself. |
376 | * |
377 | * @return A const reference to the lowest layer in the stack of layers. |
378 | * Ownership is not transferred to the caller. |
379 | */ |
380 | const lowest_layer_type& lowest_layer() const |
381 | { |
382 | return *this; |
383 | } |
384 | |
385 | /// Open the serial port using the specified device name. |
386 | /** |
387 | * This function opens the serial port for the specified device name. |
388 | * |
389 | * @param device The platform-specific device name. |
390 | * |
391 | * @throws boost::system::system_error Thrown on failure. |
392 | */ |
393 | void open(const std::string& device) |
394 | { |
395 | boost::system::error_code ec; |
396 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
397 | boost::asio::detail::throw_error(err: ec, location: "open" ); |
398 | } |
399 | |
400 | /// Open the serial port using the specified device name. |
401 | /** |
402 | * This function opens the serial port using the given platform-specific |
403 | * device name. |
404 | * |
405 | * @param device The platform-specific device name. |
406 | * |
407 | * @param ec Set the indicate what error occurred, if any. |
408 | */ |
409 | BOOST_ASIO_SYNC_OP_VOID open(const std::string& device, |
410 | boost::system::error_code& ec) |
411 | { |
412 | impl_.get_service().open(impl_.get_implementation(), device, ec); |
413 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
414 | } |
415 | |
416 | /// Assign an existing native serial port to the serial port. |
417 | /* |
418 | * This function opens the serial port to hold an existing native serial port. |
419 | * |
420 | * @param native_serial_port A native serial port. |
421 | * |
422 | * @throws boost::system::system_error Thrown on failure. |
423 | */ |
424 | void assign(const native_handle_type& native_serial_port) |
425 | { |
426 | boost::system::error_code ec; |
427 | impl_.get_service().assign(impl_.get_implementation(), |
428 | native_serial_port, ec); |
429 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
430 | } |
431 | |
432 | /// Assign an existing native serial port to the serial port. |
433 | /* |
434 | * This function opens the serial port to hold an existing native serial port. |
435 | * |
436 | * @param native_serial_port A native serial port. |
437 | * |
438 | * @param ec Set to indicate what error occurred, if any. |
439 | */ |
440 | BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, |
441 | boost::system::error_code& ec) |
442 | { |
443 | impl_.get_service().assign(impl_.get_implementation(), |
444 | native_serial_port, ec); |
445 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
446 | } |
447 | |
448 | /// Determine whether the serial port is open. |
449 | bool is_open() const |
450 | { |
451 | return impl_.get_service().is_open(impl_.get_implementation()); |
452 | } |
453 | |
454 | /// Close the serial port. |
455 | /** |
456 | * This function is used to close the serial port. Any asynchronous read or |
457 | * write operations will be cancelled immediately, and will complete with the |
458 | * boost::asio::error::operation_aborted error. |
459 | * |
460 | * @throws boost::system::system_error Thrown on failure. |
461 | */ |
462 | void close() |
463 | { |
464 | boost::system::error_code ec; |
465 | impl_.get_service().close(impl_.get_implementation(), ec); |
466 | boost::asio::detail::throw_error(err: ec, location: "close" ); |
467 | } |
468 | |
469 | /// Close the serial port. |
470 | /** |
471 | * This function is used to close the serial port. Any asynchronous read or |
472 | * write operations will be cancelled immediately, and will complete with the |
473 | * boost::asio::error::operation_aborted error. |
474 | * |
475 | * @param ec Set to indicate what error occurred, if any. |
476 | */ |
477 | BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) |
478 | { |
479 | impl_.get_service().close(impl_.get_implementation(), ec); |
480 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
481 | } |
482 | |
483 | /// Get the native serial port representation. |
484 | /** |
485 | * This function may be used to obtain the underlying representation of the |
486 | * serial port. This is intended to allow access to native serial port |
487 | * functionality that is not otherwise provided. |
488 | */ |
489 | native_handle_type native_handle() |
490 | { |
491 | return impl_.get_service().native_handle(impl_.get_implementation()); |
492 | } |
493 | |
494 | /// Cancel all asynchronous operations associated with the serial port. |
495 | /** |
496 | * This function causes all outstanding asynchronous read or write operations |
497 | * to finish immediately, and the handlers for cancelled operations will be |
498 | * passed the boost::asio::error::operation_aborted error. |
499 | * |
500 | * @throws boost::system::system_error Thrown on failure. |
501 | */ |
502 | void cancel() |
503 | { |
504 | boost::system::error_code ec; |
505 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
506 | boost::asio::detail::throw_error(err: ec, location: "cancel" ); |
507 | } |
508 | |
509 | /// Cancel all asynchronous operations associated with the serial port. |
510 | /** |
511 | * This function causes all outstanding asynchronous read or write operations |
512 | * to finish immediately, and the handlers for cancelled operations will be |
513 | * passed the boost::asio::error::operation_aborted error. |
514 | * |
515 | * @param ec Set to indicate what error occurred, if any. |
516 | */ |
517 | BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) |
518 | { |
519 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
520 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
521 | } |
522 | |
523 | /// Send a break sequence to the serial port. |
524 | /** |
525 | * This function causes a break sequence of platform-specific duration to be |
526 | * sent out the serial port. |
527 | * |
528 | * @throws boost::system::system_error Thrown on failure. |
529 | */ |
530 | void send_break() |
531 | { |
532 | boost::system::error_code ec; |
533 | impl_.get_service().send_break(impl_.get_implementation(), ec); |
534 | boost::asio::detail::throw_error(err: ec, location: "send_break" ); |
535 | } |
536 | |
537 | /// Send a break sequence to the serial port. |
538 | /** |
539 | * This function causes a break sequence of platform-specific duration to be |
540 | * sent out the serial port. |
541 | * |
542 | * @param ec Set to indicate what error occurred, if any. |
543 | */ |
544 | BOOST_ASIO_SYNC_OP_VOID send_break(boost::system::error_code& ec) |
545 | { |
546 | impl_.get_service().send_break(impl_.get_implementation(), ec); |
547 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
548 | } |
549 | |
550 | /// Set an option on the serial port. |
551 | /** |
552 | * This function is used to set an option on the serial port. |
553 | * |
554 | * @param option The option value to be set on the serial port. |
555 | * |
556 | * @throws boost::system::system_error Thrown on failure. |
557 | * |
558 | * @sa SettableSerialPortOption @n |
559 | * boost::asio::serial_port_base::baud_rate @n |
560 | * boost::asio::serial_port_base::flow_control @n |
561 | * boost::asio::serial_port_base::parity @n |
562 | * boost::asio::serial_port_base::stop_bits @n |
563 | * boost::asio::serial_port_base::character_size |
564 | */ |
565 | template <typename SettableSerialPortOption> |
566 | void set_option(const SettableSerialPortOption& option) |
567 | { |
568 | boost::system::error_code ec; |
569 | impl_.get_service().set_option(impl_.get_implementation(), option, ec); |
570 | boost::asio::detail::throw_error(err: ec, location: "set_option" ); |
571 | } |
572 | |
573 | /// Set an option on the serial port. |
574 | /** |
575 | * This function is used to set an option on the serial port. |
576 | * |
577 | * @param option The option value to be set on the serial port. |
578 | * |
579 | * @param ec Set to indicate what error occurred, if any. |
580 | * |
581 | * @sa SettableSerialPortOption @n |
582 | * boost::asio::serial_port_base::baud_rate @n |
583 | * boost::asio::serial_port_base::flow_control @n |
584 | * boost::asio::serial_port_base::parity @n |
585 | * boost::asio::serial_port_base::stop_bits @n |
586 | * boost::asio::serial_port_base::character_size |
587 | */ |
588 | template <typename SettableSerialPortOption> |
589 | BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, |
590 | boost::system::error_code& ec) |
591 | { |
592 | impl_.get_service().set_option(impl_.get_implementation(), option, ec); |
593 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
594 | } |
595 | |
596 | /// Get an option from the serial port. |
597 | /** |
598 | * This function is used to get the current value of an option on the serial |
599 | * port. |
600 | * |
601 | * @param option The option value to be obtained from the serial port. |
602 | * |
603 | * @throws boost::system::system_error Thrown on failure. |
604 | * |
605 | * @sa GettableSerialPortOption @n |
606 | * boost::asio::serial_port_base::baud_rate @n |
607 | * boost::asio::serial_port_base::flow_control @n |
608 | * boost::asio::serial_port_base::parity @n |
609 | * boost::asio::serial_port_base::stop_bits @n |
610 | * boost::asio::serial_port_base::character_size |
611 | */ |
612 | template <typename GettableSerialPortOption> |
613 | void get_option(GettableSerialPortOption& option) const |
614 | { |
615 | boost::system::error_code ec; |
616 | impl_.get_service().get_option(impl_.get_implementation(), option, ec); |
617 | boost::asio::detail::throw_error(err: ec, location: "get_option" ); |
618 | } |
619 | |
620 | /// Get an option from the serial port. |
621 | /** |
622 | * This function is used to get the current value of an option on the serial |
623 | * port. |
624 | * |
625 | * @param option The option value to be obtained from the serial port. |
626 | * |
627 | * @param ec Set to indicate what error occurred, if any. |
628 | * |
629 | * @sa GettableSerialPortOption @n |
630 | * boost::asio::serial_port_base::baud_rate @n |
631 | * boost::asio::serial_port_base::flow_control @n |
632 | * boost::asio::serial_port_base::parity @n |
633 | * boost::asio::serial_port_base::stop_bits @n |
634 | * boost::asio::serial_port_base::character_size |
635 | */ |
636 | template <typename GettableSerialPortOption> |
637 | BOOST_ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, |
638 | boost::system::error_code& ec) const |
639 | { |
640 | impl_.get_service().get_option(impl_.get_implementation(), option, ec); |
641 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
642 | } |
643 | |
644 | /// Write some data to the serial port. |
645 | /** |
646 | * This function is used to write data to the serial port. The function call |
647 | * will block until one or more bytes of the data has been written |
648 | * successfully, or until an error occurs. |
649 | * |
650 | * @param buffers One or more data buffers to be written to the serial port. |
651 | * |
652 | * @returns The number of bytes written. |
653 | * |
654 | * @throws boost::system::system_error Thrown on failure. An error code of |
655 | * boost::asio::error::eof indicates that the connection was closed by the |
656 | * peer. |
657 | * |
658 | * @note The write_some operation may not transmit all of the data to the |
659 | * peer. Consider using the @ref write function if you need to ensure that |
660 | * all data is written before the blocking operation completes. |
661 | * |
662 | * @par Example |
663 | * To write a single data buffer use the @ref buffer function as follows: |
664 | * @code |
665 | * basic_serial_port.write_some(boost::asio::buffer(data, size)); |
666 | * @endcode |
667 | * See the @ref buffer documentation for information on writing multiple |
668 | * buffers in one go, and how to use it with arrays, boost::array or |
669 | * std::vector. |
670 | */ |
671 | template <typename ConstBufferSequence> |
672 | std::size_t write_some(const ConstBufferSequence& buffers) |
673 | { |
674 | boost::system::error_code ec; |
675 | std::size_t s = impl_.get_service().write_some( |
676 | impl_.get_implementation(), buffers, ec); |
677 | boost::asio::detail::throw_error(err: ec, location: "write_some" ); |
678 | return s; |
679 | } |
680 | |
681 | /// Write some data to the serial port. |
682 | /** |
683 | * This function is used to write data to the serial port. The function call |
684 | * will block until one or more bytes of the data has been written |
685 | * successfully, or until an error occurs. |
686 | * |
687 | * @param buffers One or more data buffers to be written to the serial port. |
688 | * |
689 | * @param ec Set to indicate what error occurred, if any. |
690 | * |
691 | * @returns The number of bytes written. Returns 0 if an error occurred. |
692 | * |
693 | * @note The write_some operation may not transmit all of the data to the |
694 | * peer. Consider using the @ref write function if you need to ensure that |
695 | * all data is written before the blocking operation completes. |
696 | */ |
697 | template <typename ConstBufferSequence> |
698 | std::size_t write_some(const ConstBufferSequence& buffers, |
699 | boost::system::error_code& ec) |
700 | { |
701 | return impl_.get_service().write_some( |
702 | impl_.get_implementation(), buffers, ec); |
703 | } |
704 | |
705 | /// Start an asynchronous write. |
706 | /** |
707 | * This function is used to asynchronously write data to the serial port. |
708 | * It is an initiating function for an @ref asynchronous_operation, and always |
709 | * returns immediately. |
710 | * |
711 | * @param buffers One or more data buffers to be written to the serial port. |
712 | * Although the buffers object may be copied as necessary, ownership of the |
713 | * underlying memory blocks is retained by the caller, which must guarantee |
714 | * that they remain valid until the completion handler is called. |
715 | * |
716 | * @param token The @ref completion_token that will be used to produce a |
717 | * completion handler, which will be called when the write completes. |
718 | * Potential completion tokens include @ref use_future, @ref use_awaitable, |
719 | * @ref yield_context, or a function object with the correct completion |
720 | * signature. The function signature of the completion handler must be: |
721 | * @code void handler( |
722 | * const boost::system::error_code& error, // Result of operation. |
723 | * std::size_t bytes_transferred // Number of bytes written. |
724 | * ); @endcode |
725 | * Regardless of whether the asynchronous operation completes immediately or |
726 | * not, the completion handler will not be invoked from within this function. |
727 | * On immediate completion, invocation of the handler will be performed in a |
728 | * manner equivalent to using boost::asio::post(). |
729 | * |
730 | * @par Completion Signature |
731 | * @code void(boost::system::error_code, std::size_t) @endcode |
732 | * |
733 | * @note The write operation may not transmit all of the data to the peer. |
734 | * Consider using the @ref async_write function if you need to ensure that all |
735 | * data is written before the asynchronous operation completes. |
736 | * |
737 | * @par Example |
738 | * To write a single data buffer use the @ref buffer function as follows: |
739 | * @code |
740 | * basic_serial_port.async_write_some( |
741 | * boost::asio::buffer(data, size), handler); |
742 | * @endcode |
743 | * See the @ref buffer documentation for information on writing multiple |
744 | * buffers in one go, and how to use it with arrays, boost::array or |
745 | * std::vector. |
746 | * |
747 | * @par Per-Operation Cancellation |
748 | * On POSIX or Windows operating systems, this asynchronous operation supports |
749 | * cancellation for the following boost::asio::cancellation_type values: |
750 | * |
751 | * @li @c cancellation_type::terminal |
752 | * |
753 | * @li @c cancellation_type::partial |
754 | * |
755 | * @li @c cancellation_type::total |
756 | */ |
757 | template <typename ConstBufferSequence, |
758 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
759 | std::size_t)) WriteToken = default_completion_token_t<executor_type>> |
760 | auto async_write_some(const ConstBufferSequence& buffers, |
761 | WriteToken&& token = default_completion_token_t<executor_type>()) |
762 | -> decltype( |
763 | async_initiate<WriteToken, |
764 | void (boost::system::error_code, std::size_t)>( |
765 | declval<initiate_async_write_some>(), token, buffers)) |
766 | { |
767 | return async_initiate<WriteToken, |
768 | void (boost::system::error_code, std::size_t)>( |
769 | initiate_async_write_some(this), token, buffers); |
770 | } |
771 | |
772 | /// Read some data from the serial port. |
773 | /** |
774 | * This function is used to read data from the serial port. The function |
775 | * call will block until one or more bytes of data has been read successfully, |
776 | * or until an error occurs. |
777 | * |
778 | * @param buffers One or more buffers into which the data will be read. |
779 | * |
780 | * @returns The number of bytes read. |
781 | * |
782 | * @throws boost::system::system_error Thrown on failure. An error code of |
783 | * boost::asio::error::eof indicates that the connection was closed by the |
784 | * peer. |
785 | * |
786 | * @note The read_some operation may not read all of the requested number of |
787 | * bytes. Consider using the @ref read function if you need to ensure that |
788 | * the requested amount of data is read before the blocking operation |
789 | * completes. |
790 | * |
791 | * @par Example |
792 | * To read into a single data buffer use the @ref buffer function as follows: |
793 | * @code |
794 | * basic_serial_port.read_some(boost::asio::buffer(data, size)); |
795 | * @endcode |
796 | * See the @ref buffer documentation for information on reading into multiple |
797 | * buffers in one go, and how to use it with arrays, boost::array or |
798 | * std::vector. |
799 | */ |
800 | template <typename MutableBufferSequence> |
801 | std::size_t read_some(const MutableBufferSequence& buffers) |
802 | { |
803 | boost::system::error_code ec; |
804 | std::size_t s = impl_.get_service().read_some( |
805 | impl_.get_implementation(), buffers, ec); |
806 | boost::asio::detail::throw_error(err: ec, location: "read_some" ); |
807 | return s; |
808 | } |
809 | |
810 | /// Read some data from the serial port. |
811 | /** |
812 | * This function is used to read data from the serial port. The function |
813 | * call will block until one or more bytes of data has been read successfully, |
814 | * or until an error occurs. |
815 | * |
816 | * @param buffers One or more buffers into which the data will be read. |
817 | * |
818 | * @param ec Set to indicate what error occurred, if any. |
819 | * |
820 | * @returns The number of bytes read. Returns 0 if an error occurred. |
821 | * |
822 | * @note The read_some operation may not read all of the requested number of |
823 | * bytes. Consider using the @ref read function if you need to ensure that |
824 | * the requested amount of data is read before the blocking operation |
825 | * completes. |
826 | */ |
827 | template <typename MutableBufferSequence> |
828 | std::size_t read_some(const MutableBufferSequence& buffers, |
829 | boost::system::error_code& ec) |
830 | { |
831 | return impl_.get_service().read_some( |
832 | impl_.get_implementation(), buffers, ec); |
833 | } |
834 | |
835 | /// Start an asynchronous read. |
836 | /** |
837 | * This function is used to asynchronously read data from the serial port. |
838 | * It is an initiating function for an @ref asynchronous_operation, and always |
839 | * returns immediately. |
840 | * |
841 | * @param buffers One or more buffers into which the data will be read. |
842 | * Although the buffers object may be copied as necessary, ownership of the |
843 | * underlying memory blocks is retained by the caller, which must guarantee |
844 | * that they remain valid until the completion handler is called. |
845 | * |
846 | * @param token The @ref completion_token that will be used to produce a |
847 | * completion handler, which will be called when the read completes. |
848 | * Potential completion tokens include @ref use_future, @ref use_awaitable, |
849 | * @ref yield_context, or a function object with the correct completion |
850 | * signature. The function signature of the completion handler must be: |
851 | * @code void handler( |
852 | * const boost::system::error_code& error, // Result of operation. |
853 | * std::size_t bytes_transferred // Number of bytes read. |
854 | * ); @endcode |
855 | * Regardless of whether the asynchronous operation completes immediately or |
856 | * not, the completion handler will not be invoked from within this function. |
857 | * On immediate completion, invocation of the handler will be performed in a |
858 | * manner equivalent to using boost::asio::post(). |
859 | * |
860 | * @par Completion Signature |
861 | * @code void(boost::system::error_code, std::size_t) @endcode |
862 | * |
863 | * @note The read operation may not read all of the requested number of bytes. |
864 | * Consider using the @ref async_read function if you need to ensure that the |
865 | * requested amount of data is read before the asynchronous operation |
866 | * completes. |
867 | * |
868 | * @par Example |
869 | * To read into a single data buffer use the @ref buffer function as follows: |
870 | * @code |
871 | * basic_serial_port.async_read_some( |
872 | * boost::asio::buffer(data, size), handler); |
873 | * @endcode |
874 | * See the @ref buffer documentation for information on reading into multiple |
875 | * buffers in one go, and how to use it with arrays, boost::array or |
876 | * std::vector. |
877 | * |
878 | * @par Per-Operation Cancellation |
879 | * On POSIX or Windows operating systems, this asynchronous operation supports |
880 | * cancellation for the following boost::asio::cancellation_type values: |
881 | * |
882 | * @li @c cancellation_type::terminal |
883 | * |
884 | * @li @c cancellation_type::partial |
885 | * |
886 | * @li @c cancellation_type::total |
887 | */ |
888 | template <typename MutableBufferSequence, |
889 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, |
890 | std::size_t)) ReadToken = default_completion_token_t<executor_type>> |
891 | auto async_read_some(const MutableBufferSequence& buffers, |
892 | ReadToken&& token = default_completion_token_t<executor_type>()) |
893 | -> decltype( |
894 | async_initiate<ReadToken, |
895 | void (boost::system::error_code, std::size_t)>( |
896 | declval<initiate_async_read_some>(), token, buffers)) |
897 | { |
898 | return async_initiate<ReadToken, |
899 | void (boost::system::error_code, std::size_t)>( |
900 | initiate_async_read_some(this), token, buffers); |
901 | } |
902 | |
903 | private: |
904 | // Disallow copying and assignment. |
905 | basic_serial_port(const basic_serial_port&) = delete; |
906 | basic_serial_port& operator=(const basic_serial_port&) = delete; |
907 | |
908 | class initiate_async_write_some |
909 | { |
910 | public: |
911 | typedef Executor executor_type; |
912 | |
913 | explicit initiate_async_write_some(basic_serial_port* self) |
914 | : self_(self) |
915 | { |
916 | } |
917 | |
918 | const executor_type& get_executor() const noexcept |
919 | { |
920 | return self_->get_executor(); |
921 | } |
922 | |
923 | template <typename WriteHandler, typename ConstBufferSequence> |
924 | void operator()(WriteHandler&& handler, |
925 | const ConstBufferSequence& buffers) const |
926 | { |
927 | // If you get an error on the following line it means that your handler |
928 | // does not meet the documented type requirements for a WriteHandler. |
929 | BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; |
930 | |
931 | detail::non_const_lvalue<WriteHandler> handler2(handler); |
932 | self_->impl_.get_service().async_write_some( |
933 | self_->impl_.get_implementation(), buffers, |
934 | handler2.value, self_->impl_.get_executor()); |
935 | } |
936 | |
937 | private: |
938 | basic_serial_port* self_; |
939 | }; |
940 | |
941 | class initiate_async_read_some |
942 | { |
943 | public: |
944 | typedef Executor executor_type; |
945 | |
946 | explicit initiate_async_read_some(basic_serial_port* self) |
947 | : self_(self) |
948 | { |
949 | } |
950 | |
951 | const executor_type& get_executor() const noexcept |
952 | { |
953 | return self_->get_executor(); |
954 | } |
955 | |
956 | template <typename ReadHandler, typename MutableBufferSequence> |
957 | void operator()(ReadHandler&& handler, |
958 | const MutableBufferSequence& buffers) const |
959 | { |
960 | // If you get an error on the following line it means that your handler |
961 | // does not meet the documented type requirements for a ReadHandler. |
962 | BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; |
963 | |
964 | detail::non_const_lvalue<ReadHandler> handler2(handler); |
965 | self_->impl_.get_service().async_read_some( |
966 | self_->impl_.get_implementation(), buffers, |
967 | handler2.value, self_->impl_.get_executor()); |
968 | } |
969 | |
970 | private: |
971 | basic_serial_port* self_; |
972 | }; |
973 | |
974 | #if defined(BOOST_ASIO_HAS_IOCP) |
975 | detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_; |
976 | #else |
977 | detail::io_object_impl<detail::posix_serial_port_service, Executor> impl_; |
978 | #endif |
979 | }; |
980 | |
981 | } // namespace asio |
982 | } // namespace boost |
983 | |
984 | #include <boost/asio/detail/pop_options.hpp> |
985 | |
986 | #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) |
987 | // || defined(GENERATING_DOCUMENTATION) |
988 | |
989 | #endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP |
990 | |