serial_port.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_SERIAL_PORT_HPP__
  11. #define __ASIO2_SERIAL_PORT_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <asio2/base/detail/push_options.hpp>
  16. #include <cstdint>
  17. #include <memory>
  18. #include <chrono>
  19. #include <functional>
  20. #include <atomic>
  21. #include <string>
  22. #include <string_view>
  23. #include <queue>
  24. #include <any>
  25. #include <future>
  26. #include <tuple>
  27. #include <asio2/base/iopool.hpp>
  28. #include <asio2/base/listener.hpp>
  29. #include <asio2/base/define.hpp>
  30. #include <asio2/base/detail/object.hpp>
  31. #include <asio2/base/detail/allocator.hpp>
  32. #include <asio2/base/detail/util.hpp>
  33. #include <asio2/base/detail/buffer_wrap.hpp>
  34. #include <asio2/base/detail/ecs.hpp>
  35. #include <asio2/base/impl/thread_id_cp.hpp>
  36. #include <asio2/base/impl/alive_time_cp.hpp>
  37. #include <asio2/base/impl/user_data_cp.hpp>
  38. #include <asio2/base/impl/socket_cp.hpp>
  39. #include <asio2/base/impl/user_timer_cp.hpp>
  40. #include <asio2/base/impl/post_cp.hpp>
  41. #include <asio2/base/impl/event_queue_cp.hpp>
  42. #include <asio2/base/impl/condition_event_cp.hpp>
  43. #include <asio2/base/impl/send_cp.hpp>
  44. #include <asio2/tcp/impl/tcp_send_op.hpp>
  45. #include <asio2/tcp/impl/tcp_recv_op.hpp>
  46. #include <asio2/component/rdc/rdc_call_cp.hpp>
  47. namespace asio2::detail
  48. {
  49. struct template_args_serial_port
  50. {
  51. using socket_t = asio::serial_port;
  52. using buffer_t = asio::streambuf;
  53. using send_data_t = std::string_view;
  54. using recv_data_t = std::string_view;
  55. };
  56. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  57. ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE;
  58. /**
  59. * The serial_port class provides a wrapper over serial port functionality.
  60. */
  61. template<class derived_t, class args_t = template_args_serial_port>
  62. class serial_port_impl_t
  63. : public object_t <derived_t >
  64. , public iopool_cp <derived_t, args_t>
  65. , public thread_id_cp <derived_t, args_t>
  66. , public event_queue_cp <derived_t, args_t>
  67. , public user_data_cp <derived_t, args_t>
  68. , public alive_time_cp <derived_t, args_t>
  69. , public user_timer_cp <derived_t, args_t>
  70. , public send_cp <derived_t, args_t>
  71. , public tcp_send_op <derived_t, args_t>
  72. , public tcp_recv_op <derived_t, args_t>
  73. , public post_cp <derived_t, args_t>
  74. , public condition_event_cp<derived_t, args_t>
  75. , public rdc_call_cp <derived_t, args_t>
  76. {
  77. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  78. ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE;
  79. public:
  80. using super = object_t <derived_t >;
  81. using self = serial_port_impl_t<derived_t, args_t>;
  82. using iopoolcp = iopool_cp <derived_t, args_t>;
  83. using args_type = args_t;
  84. using socket_type = typename args_t::socket_t;
  85. using buffer_type = typename args_t::buffer_t;
  86. using send_data_t = typename args_t::send_data_t;
  87. using recv_data_t = typename args_t::recv_data_t;
  88. /**
  89. * @brief constructor
  90. */
  91. explicit serial_port_impl_t(
  92. std::size_t init_buf_size = 1024,
  93. std::size_t max_buf_size = max_buffer_size,
  94. std::size_t concurrency = 1
  95. )
  96. : super()
  97. , iopool_cp <derived_t, args_t>(concurrency)
  98. , event_queue_cp <derived_t, args_t>()
  99. , user_data_cp <derived_t, args_t>()
  100. , alive_time_cp <derived_t, args_t>()
  101. , user_timer_cp <derived_t, args_t>()
  102. , send_cp <derived_t, args_t>()
  103. , tcp_send_op <derived_t, args_t>()
  104. , tcp_recv_op <derived_t, args_t>()
  105. , post_cp <derived_t, args_t>()
  106. , condition_event_cp<derived_t, args_t>()
  107. , rdc_call_cp <derived_t, args_t>()
  108. , rallocator_()
  109. , wallocator_()
  110. , listener_ ()
  111. , io_ (iopoolcp::_get_io(0))
  112. , buffer_ (init_buf_size, max_buf_size)
  113. , socket_ (std::make_shared<socket_type>(iopoolcp::_get_io(0)->context()))
  114. {
  115. }
  116. template<class Scheduler, std::enable_if_t<!std::is_integral_v<detail::remove_cvref_t<Scheduler>>, int> = 0>
  117. explicit serial_port_impl_t(
  118. std::size_t init_buf_size,
  119. std::size_t max_buf_size,
  120. Scheduler&& scheduler
  121. )
  122. : super()
  123. , iopool_cp <derived_t, args_t>(std::forward<Scheduler>(scheduler))
  124. , event_queue_cp <derived_t, args_t>()
  125. , user_data_cp <derived_t, args_t>()
  126. , alive_time_cp <derived_t, args_t>()
  127. , user_timer_cp <derived_t, args_t>()
  128. , send_cp <derived_t, args_t>()
  129. , tcp_send_op <derived_t, args_t>()
  130. , tcp_recv_op <derived_t, args_t>()
  131. , post_cp <derived_t, args_t>()
  132. , condition_event_cp<derived_t, args_t>()
  133. , rdc_call_cp <derived_t, args_t>()
  134. , rallocator_()
  135. , wallocator_()
  136. , listener_ ()
  137. , io_ (iopoolcp::_get_io(0))
  138. , buffer_ (init_buf_size, max_buf_size)
  139. , socket_ (std::make_shared<socket_type>(iopoolcp::_get_io(0)->context()))
  140. {
  141. }
  142. template<class Scheduler, std::enable_if_t<!std::is_integral_v<detail::remove_cvref_t<Scheduler>>, int> = 0>
  143. explicit serial_port_impl_t(Scheduler&& scheduler)
  144. : serial_port_impl_t(1024, max_buffer_size, std::forward<Scheduler>(scheduler))
  145. {
  146. }
  147. /**
  148. * @brief destructor
  149. */
  150. ~serial_port_impl_t()
  151. {
  152. this->stop();
  153. }
  154. /**
  155. * @brief start
  156. * @param device - The platform-specific device name for this serial, example "/dev/ttyS0" or "COM1"
  157. * @param baud_rate - Communication speed, example 9600 or 115200
  158. * @param condition - The delimiter condition.Valid value types include the following:
  159. * char,std::string,std::string_view,
  160. * function:std::pair<iterator, bool> match_condition(iterator begin, iterator end),
  161. * asio::transfer_at_least,asio::transfer_exactly
  162. * more details see asio::read_until
  163. */
  164. template<typename String, typename StrOrInt, typename... Args>
  165. inline bool start(String&& device, StrOrInt&& baud_rate, Args&&... args)
  166. {
  167. return this->derived()._do_start(
  168. std::forward<String>(device), std::forward<StrOrInt>(baud_rate),
  169. ecs_helper::make_ecs(asio::transfer_at_least(1), std::forward<Args>(args)...));
  170. }
  171. /**
  172. * @brief stop
  173. * You can call this function in the communication thread and anywhere to stop the serial port.
  174. * If this function is called in the communication thread, it will post a asynchronous
  175. * event into the event queue, then return immediately.
  176. * If this function is called not in the communication thread, it will blocking forever
  177. * util the serial port is stopped completed.
  178. */
  179. inline void stop()
  180. {
  181. if (this->is_iopool_stopped())
  182. return;
  183. derived_t& derive = this->derived();
  184. derive.io_->unregobj(&derive);
  185. // use promise to get the result of stop
  186. std::promise<state_t> promise;
  187. std::future<state_t> future = promise.get_future();
  188. // use derfer to ensure the promise's value must be seted.
  189. detail::defer_event pg
  190. {
  191. [this, p = std::move(promise)]() mutable
  192. {
  193. p.set_value(this->state_.load());
  194. }
  195. };
  196. derive.post_event([&derive, this_ptr = derive.selfptr(), pg = std::move(pg)]
  197. (event_queue_guard<derived_t> g) mutable
  198. {
  199. derive._do_disconnect(asio::error::operation_aborted, std::move(this_ptr), defer_event
  200. {
  201. [pg = std::move(pg)](event_queue_guard<derived_t> g) mutable
  202. {
  203. detail::ignore_unused(pg, g);
  204. // the "pg" should destroyed before the "g", otherwise if the "g"
  205. // is destroyed before "pg", the next event maybe called, then the
  206. // state maybe change to not stopped.
  207. {
  208. [[maybe_unused]] detail::defer_event t{ std::move(pg) };
  209. }
  210. }, std::move(g)
  211. });
  212. });
  213. while (!derive.running_in_this_thread())
  214. {
  215. std::future_status status = future.wait_for(std::chrono::milliseconds(100));
  216. if (status == std::future_status::ready)
  217. {
  218. ASIO2_ASSERT(future.get() == state_t::stopped);
  219. break;
  220. }
  221. else
  222. {
  223. if (derive.get_thread_id() == std::thread::id{})
  224. break;
  225. if (derive.io_->context().stopped())
  226. break;
  227. }
  228. }
  229. this->stop_iopool();
  230. }
  231. /**
  232. * @brief destroy the content of all member variables, this is used for solve the memory leaks.
  233. * After this function is called, this class object cannot be used again.
  234. */
  235. inline void destroy()
  236. {
  237. derived_t& derive = this->derived();
  238. derive.socket_.reset();
  239. derive.io_.reset();
  240. derive.listener_.clear();
  241. derive.destroy_iopool();
  242. }
  243. /**
  244. * @brief check whether the client is started
  245. */
  246. inline bool is_started() const
  247. {
  248. return (this->state_ == state_t::started && this->socket_->is_open());
  249. }
  250. /**
  251. * @brief check whether the client is stopped
  252. */
  253. inline bool is_stopped() const
  254. {
  255. return (this->state_ == state_t::stopped && !this->socket_->is_open());
  256. }
  257. public:
  258. /**
  259. * @brief bind recv listener
  260. * @param fun - a user defined callback function.
  261. * @param obj - a pointer or reference to a class object, this parameter can be none.
  262. * @li if fun is nonmember function, the obj param must be none, otherwise the obj must be the
  263. * the class object's pointer or reference.
  264. * void on_recv(std::string_view data){...}
  265. * or a lumbda function like this :
  266. * [&](std::string_view data){...}
  267. */
  268. template<class F, class ...C>
  269. inline derived_t & bind_recv(F&& fun, C&&... obj)
  270. {
  271. this->listener_.bind(event_type::recv,
  272. observer_t<std::string_view>(std::forward<F>(fun), std::forward<C>(obj)...));
  273. return (this->derived());
  274. }
  275. /**
  276. * @brief bind init listener,we should set socket options at here
  277. * @param fun - a user defined callback function.
  278. * @param obj - a pointer or reference to a class object, this parameter can be none.
  279. * @li if fun is nonmember function, the obj param must be none, otherwise the obj must be the
  280. * the class object's pointer or reference.
  281. * void on_init(){...}
  282. * or a lumbda function like this :
  283. * [&](){...}
  284. */
  285. template<class F, class ...C>
  286. inline derived_t & bind_init(F&& fun, C&&... obj)
  287. {
  288. this->listener_.bind(event_type::init,
  289. observer_t<>(std::forward<F>(fun), std::forward<C>(obj)...));
  290. return (this->derived());
  291. }
  292. /**
  293. * @brief bind start listener
  294. * @param fun - a user defined callback function.
  295. * @param obj - a pointer or reference to a class object, this parameter can be none.
  296. * @li if fun is nonmember function, the obj param must be none, otherwise the obj must be the
  297. * the class object's pointer or reference.
  298. * This notification is called after the server starts up, whether successful or unsuccessful
  299. * Function signature : void()
  300. */
  301. template<class F, class ...C>
  302. inline derived_t & bind_start(F&& fun, C&&... obj)
  303. {
  304. this->listener_.bind(event_type::start,
  305. observer_t<>(std::forward<F>(fun), std::forward<C>(obj)...));
  306. return (this->derived());
  307. }
  308. /**
  309. * @brief bind stop listener
  310. * @param fun - a user defined callback function.
  311. * @param obj - a pointer or reference to a class object, this parameter can be none.
  312. * @li if fun is nonmember function, the obj param must be none, otherwise the obj must be the
  313. * the class object's pointer or reference.
  314. * This notification is called before the server is ready to stop
  315. * Function signature : void()
  316. */
  317. template<class F, class ...C>
  318. inline derived_t & bind_stop(F&& fun, C&&... obj)
  319. {
  320. this->listener_.bind(event_type::stop,
  321. observer_t<>(std::forward<F>(fun), std::forward<C>(obj)...));
  322. return (this->derived());
  323. }
  324. public:
  325. /**
  326. * @brief get the socket object reference
  327. */
  328. inline socket_type & socket() noexcept { return *(this->socket_); }
  329. /**
  330. * @brief get the socket object reference
  331. */
  332. inline const socket_type & socket() const noexcept { return *(this->socket_); }
  333. /**
  334. * @brief get the stream object reference
  335. */
  336. inline socket_type & stream() noexcept { return *(this->socket_); }
  337. /**
  338. * @brief get the stream object reference
  339. */
  340. inline const socket_type & stream() const noexcept { return *(this->socket_); }
  341. /**
  342. * This function is used to set an option on the serial port.
  343. *
  344. * @param option - The option value to be set on the serial port.
  345. * @li
  346. * asio::serial_port::baud_rate
  347. * asio::serial_port::flow_control
  348. * asio::serial_port::parity
  349. * asio::serial_port::stop_bits
  350. * asio::serial_port::character_size
  351. */
  352. template <typename SettableSerialPortOption>
  353. derived_t& set_option(const SettableSerialPortOption& option) noexcept
  354. {
  355. this->socket_->set_option(option, get_last_error());
  356. return (this->derived());
  357. }
  358. /**
  359. * This function is used to get the current value of an option on the serial
  360. * port.
  361. *
  362. * @param option - The option value to be obtained from the serial port.
  363. * @li
  364. * asio::serial_port::baud_rate
  365. * asio::serial_port::flow_control
  366. * asio::serial_port::parity
  367. * asio::serial_port::stop_bits
  368. * asio::serial_port::character_size
  369. */
  370. template <typename GettableSerialPortOption>
  371. GettableSerialPortOption get_option() const
  372. {
  373. GettableSerialPortOption option{};
  374. this->socket_->get_option(option, get_last_error());
  375. return option;
  376. }
  377. /**
  378. * This function is used to get the current value of an option on the serial
  379. * port.
  380. *
  381. * @param option - The option value to be obtained from the serial port.
  382. * @li
  383. * asio::serial_port_base::baud_rate
  384. * asio::serial_port_base::flow_control
  385. * asio::serial_port_base::parity
  386. * asio::serial_port_base::stop_bits
  387. * asio::serial_port_base::character_size
  388. */
  389. template <typename GettableSerialPortOption>
  390. derived_t& get_option(GettableSerialPortOption& option)
  391. {
  392. this->socket_->get_option(option, get_last_error());
  393. return (this->derived());
  394. }
  395. protected:
  396. template<typename String, typename StrOrInt, typename C>
  397. bool _do_start(String&& device, StrOrInt&& baud_rate, std::shared_ptr<ecs_t<C>> ecs)
  398. {
  399. derived_t& derive = this->derived();
  400. // if log is enabled, init the log first, otherwise when "Too many open files" error occurs,
  401. // the log file will be created failed too.
  402. #if defined(ASIO2_ENABLE_LOG)
  403. asio2::detail::get_logger();
  404. #endif
  405. this->start_iopool();
  406. if (!this->is_iopool_started())
  407. {
  408. set_last_error(asio::error::operation_aborted);
  409. return false;
  410. }
  411. asio::dispatch(derive.io_->context(), [&derive, this_ptr = derive.selfptr()]() mutable
  412. {
  413. detail::ignore_unused(this_ptr);
  414. // init the running thread id
  415. derive.io_->init_thread_id();
  416. });
  417. // use promise to get the result of async connect
  418. std::promise<error_code> promise;
  419. std::future<error_code> future = promise.get_future();
  420. // use derfer to ensure the promise's value must be seted.
  421. detail::defer_event pg
  422. {
  423. [promise = std::move(promise)]() mutable
  424. {
  425. promise.set_value(get_last_error());
  426. }
  427. };
  428. derive.post_event(
  429. [this, this_ptr = derive.selfptr(), ecs = std::move(ecs), pg = std::move(pg),
  430. device = std::forward<String>(device), baud_rate = std::forward<StrOrInt>(baud_rate)]
  431. (event_queue_guard<derived_t> g) mutable
  432. {
  433. derived_t& derive = this->derived();
  434. defer_event chain
  435. {
  436. [pg = std::move(pg)](event_queue_guard<derived_t> g) mutable
  437. {
  438. detail::ignore_unused(pg, g);
  439. // the "pg" should destroyed before the "g", otherwise if the "g"
  440. // is destroyed before "pg", the next event maybe called, then the
  441. // state maybe change to not stopped.
  442. {
  443. [[maybe_unused]] detail::defer_event t{ std::move(pg) };
  444. }
  445. }, std::move(g)
  446. };
  447. state_t expected = state_t::stopped;
  448. if (!this->state_.compare_exchange_strong(expected, state_t::starting))
  449. {
  450. // if the state is not stopped, set the last error to already_started
  451. set_last_error(asio::error::already_started);
  452. return;
  453. }
  454. // must read/write ecs in the io_context thread.
  455. derive.ecs_ = ecs;
  456. derive.io_->regobj(&derive);
  457. #if defined(_DEBUG) || defined(DEBUG)
  458. this->is_stop_called_ = false;
  459. #endif
  460. // convert to string maybe throw some exception.
  461. std::string d = detail::to_string(std::move(device));
  462. unsigned int b = detail::to_numeric<unsigned int>(std::move(baud_rate));
  463. expected = state_t::starting;
  464. if (!this->state_.compare_exchange_strong(expected, state_t::starting))
  465. {
  466. ASIO2_ASSERT(false);
  467. derive._handle_start(asio::error::operation_aborted,
  468. std::move(this_ptr), std::move(ecs), std::move(chain));
  469. return;
  470. }
  471. error_code ec, ec_ignore;
  472. this->socket_->cancel(ec_ignore);
  473. this->socket_->close(ec_ignore);
  474. this->socket_->open(d, ec);
  475. if (ec)
  476. {
  477. derive._handle_start(ec, std::move(this_ptr), std::move(ecs), std::move(chain));
  478. return;
  479. }
  480. this->socket_->set_option(asio::serial_port::baud_rate(b), ec_ignore);
  481. // if the ecs has remote data call mode,do some thing.
  482. derive._rdc_init(ecs);
  483. clear_last_error();
  484. derive._fire_init();
  485. // You can set other serial port parameters in on_init(bind_init) callback function like this:
  486. // sp.set_option(asio::serial_port::flow_control(serial_port::flow_control::type(flow_control)));
  487. // sp.set_option(asio::serial_port::parity(serial_port::parity::type(parity)));
  488. // sp.set_option(asio::serial_port::stop_bits(serial_port::stop_bits::type(stop_bits)));
  489. // sp.set_option(asio::serial_port::character_size(character_size));
  490. derive._handle_start(ec, std::move(this_ptr), std::move(ecs), std::move(chain));
  491. });
  492. if (!derive.io_->running_in_this_thread())
  493. {
  494. set_last_error(future.get());
  495. return static_cast<bool>(!get_last_error());
  496. }
  497. else
  498. {
  499. set_last_error(asio::error::in_progress);
  500. }
  501. // if the state is stopped , the return value is "is_started()".
  502. // if the state is stopping, the return value is false, the last error is already_started
  503. // if the state is starting, the return value is false, the last error is already_started
  504. // if the state is started , the return value is true , the last error is already_started
  505. return derive.is_started();
  506. }
  507. template<typename C, typename DeferEvent>
  508. void _handle_start(
  509. error_code ec, std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs, DeferEvent chain)
  510. {
  511. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  512. // Whether the startup succeeds or fails, always call fire_start notification
  513. state_t expected = state_t::starting;
  514. if (!ec)
  515. if (!this->state_.compare_exchange_strong(expected, state_t::started))
  516. ec = asio::error::operation_aborted;
  517. set_last_error(ec);
  518. this->derived()._fire_start(this_ptr, ecs);
  519. expected = state_t::started;
  520. if (!ec)
  521. if (!this->state_.compare_exchange_strong(expected, state_t::started))
  522. ec = asio::error::operation_aborted;
  523. if (ec)
  524. {
  525. this->derived()._do_disconnect(ec, std::move(this_ptr), std::move(chain));
  526. return;
  527. }
  528. this->derived()._start_recv(std::move(this_ptr), std::move(ecs));
  529. }
  530. template<typename E = defer_event<void, derived_t>>
  531. inline void _do_disconnect(
  532. const error_code& ec, std::shared_ptr<derived_t> this_ptr, E chain = defer_event<void, derived_t>{})
  533. {
  534. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  535. state_t expected = state_t::started;
  536. if (this->state_.compare_exchange_strong(expected, state_t::stopping))
  537. {
  538. return this->derived()._post_disconnect(ec, std::move(this_ptr), expected, std::move(chain));
  539. }
  540. expected = state_t::starting;
  541. if (this->state_.compare_exchange_strong(expected, state_t::stopping))
  542. {
  543. return this->derived()._post_disconnect(ec, std::move(this_ptr), expected, std::move(chain));
  544. }
  545. }
  546. template<typename DeferEvent>
  547. inline void _post_disconnect(
  548. const error_code& ec, std::shared_ptr<derived_t> this_ptr, state_t old_state, DeferEvent chain)
  549. {
  550. // All pending sending events will be cancelled after enter the callback below.
  551. this->derived().disp_event(
  552. [this, ec, old_state, this_ptr = std::move(this_ptr), e = chain.move_event()]
  553. (event_queue_guard<derived_t> g) mutable
  554. {
  555. detail::ignore_unused(g);
  556. this->derived()._handle_disconnect(
  557. ec, std::move(this_ptr), old_state, defer_event(std::move(e), std::move(g)));
  558. }, chain.move_guard());
  559. }
  560. template<typename DeferEvent>
  561. inline void _handle_disconnect(
  562. const error_code& ec, std::shared_ptr<derived_t> this_ptr, state_t old_state, DeferEvent chain)
  563. {
  564. set_last_error(ec);
  565. this->derived()._rdc_stop();
  566. this->derived()._do_stop(ec, std::move(this_ptr), old_state, std::move(chain));
  567. }
  568. inline void _stop_readend_timer(std::shared_ptr<derived_t> this_ptr)
  569. {
  570. detail::ignore_unused(this_ptr);
  571. }
  572. template<typename DeferEvent>
  573. inline void _do_stop(
  574. const error_code& ec, std::shared_ptr<derived_t> this_ptr, state_t old_state, DeferEvent chain)
  575. {
  576. this->derived()._post_stop(ec, std::move(this_ptr), old_state, std::move(chain));
  577. }
  578. template<typename DeferEvent>
  579. inline void _post_stop(
  580. const error_code& ec, std::shared_ptr<derived_t> this_ptr, state_t old_state, DeferEvent chain)
  581. {
  582. // All pending sending events will be cancelled after enter the callback below.
  583. this->derived().disp_event(
  584. [this, ec, old_state, this_ptr = std::move(this_ptr), e = chain.move_event()]
  585. (event_queue_guard<derived_t> g) mutable
  586. {
  587. detail::ignore_unused(g, old_state);
  588. set_last_error(ec);
  589. defer_event chain(std::move(e), std::move(g));
  590. state_t expected = state_t::stopping;
  591. if (this->state_.compare_exchange_strong(expected, state_t::stopped))
  592. {
  593. this->derived()._fire_stop(this_ptr);
  594. // call CRTP polymorphic stop
  595. this->derived()._handle_stop(ec, std::move(this_ptr), std::move(chain));
  596. }
  597. else
  598. {
  599. ASIO2_ASSERT(false);
  600. }
  601. }, chain.move_guard());
  602. }
  603. template<typename DeferEvent>
  604. inline void _handle_stop(const error_code& ec, std::shared_ptr<derived_t> this_ptr, DeferEvent chain)
  605. {
  606. detail::ignore_unused(ec, this_ptr, chain);
  607. ASIO2_ASSERT(this->state_ == state_t::stopped);
  608. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  609. // close user custom timers
  610. this->_dispatch_stop_all_timers();
  611. // close all posted timed tasks
  612. this->_dispatch_stop_all_timed_events();
  613. // close all async_events
  614. this->notify_all_condition_events();
  615. error_code ec_ignore{};
  616. this->socket_->cancel(ec_ignore);
  617. // Call close,otherwise the _handle_recv will never return
  618. this->socket_->close(ec_ignore);
  619. // clear recv buffer
  620. this->buffer().consume(this->buffer().size());
  621. // destroy user data, maybe the user data is self shared_ptr,
  622. // if don't destroy it, will cause loop reference.
  623. this->user_data_.reset();
  624. // destroy the ecs
  625. this->ecs_.reset();
  626. //
  627. this->reset_life_id();
  628. }
  629. template<typename C>
  630. inline void _start_recv(std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs)
  631. {
  632. // Connect succeeded. post recv request.
  633. asio::dispatch(this->derived().io_->context(), make_allocator(this->derived().wallocator(),
  634. [this, this_ptr = std::move(this_ptr), ecs = std::move(ecs)]() mutable
  635. {
  636. using condition_lowest_type = typename ecs_t<C>::condition_lowest_type;
  637. if constexpr (!std::is_same_v<condition_lowest_type, asio2::detail::hook_buffer_t>)
  638. {
  639. this->derived().buffer().consume(this->derived().buffer().size());
  640. }
  641. else
  642. {
  643. std::ignore = true;
  644. }
  645. this->derived()._post_recv(std::move(this_ptr), std::move(ecs));
  646. }));
  647. }
  648. template<class Data, class Callback>
  649. inline bool _do_send(Data& data, Callback&& callback)
  650. {
  651. return this->derived()._tcp_send(data, std::forward<Callback>(callback));
  652. }
  653. template<class Data>
  654. inline send_data_t _rdc_convert_to_send_data(Data& data) noexcept
  655. {
  656. auto buffer = asio::buffer(data);
  657. return send_data_t{ reinterpret_cast<
  658. std::string_view::const_pointer>(buffer.data()),buffer.size() };
  659. }
  660. template<class Invoker>
  661. inline void _rdc_invoke_with_none(const error_code& ec, Invoker& invoker)
  662. {
  663. if (invoker)
  664. invoker(ec, send_data_t{}, recv_data_t{});
  665. }
  666. template<class Invoker>
  667. inline void _rdc_invoke_with_recv(const error_code& ec, Invoker& invoker, recv_data_t data)
  668. {
  669. if (invoker)
  670. invoker(ec, send_data_t{}, data);
  671. }
  672. template<class Invoker>
  673. inline void _rdc_invoke_with_send(const error_code& ec, Invoker& invoker, send_data_t data)
  674. {
  675. if (invoker)
  676. invoker(ec, data, recv_data_t{});
  677. }
  678. protected:
  679. template<typename C>
  680. inline void _post_recv(std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs)
  681. {
  682. this->derived()._tcp_post_recv(std::move(this_ptr), std::move(ecs));
  683. }
  684. template<typename C>
  685. inline void _handle_recv(
  686. const error_code& ec, std::size_t bytes_recvd,
  687. std::shared_ptr<derived_t> this_ptr, std::shared_ptr<ecs_t<C>> ecs)
  688. {
  689. this->derived()._tcp_handle_recv(ec, bytes_recvd, std::move(this_ptr), std::move(ecs));
  690. }
  691. inline void _fire_init()
  692. {
  693. // the _fire_init must be executed in the thread 0.
  694. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  695. ASIO2_ASSERT(!get_last_error());
  696. this->listener_.notify(event_type::init);
  697. }
  698. template<typename C>
  699. inline void _fire_start(std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs)
  700. {
  701. // the _fire_start must be executed in the thread 0.
  702. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  703. #if defined(_DEBUG) || defined(DEBUG)
  704. ASIO2_ASSERT(this->is_stop_called_ == false);
  705. #endif
  706. if (!get_last_error())
  707. {
  708. this->derived()._rdc_start(this_ptr, ecs);
  709. }
  710. this->listener_.notify(event_type::start);
  711. }
  712. inline void _fire_stop(std::shared_ptr<derived_t>&)
  713. {
  714. // the _fire_stop must be executed in the thread 0.
  715. ASIO2_ASSERT(this->derived().io_->running_in_this_thread());
  716. #if defined(_DEBUG) || defined(DEBUG)
  717. this->is_stop_called_ = true;
  718. #endif
  719. this->listener_.notify(event_type::stop);
  720. }
  721. template<typename C>
  722. inline void _fire_recv(
  723. std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs, std::string_view data)
  724. {
  725. data = detail::call_data_filter_before_recv(this->derived(), data);
  726. this->listener_.notify(event_type::recv, data);
  727. this->derived()._rdc_handle_recv(this_ptr, ecs, data);
  728. }
  729. public:
  730. /**
  731. * @brief set the default remote call timeout for rpc/rdc
  732. */
  733. template<class Rep, class Period>
  734. inline derived_t & set_default_timeout(std::chrono::duration<Rep, Period> duration) noexcept
  735. {
  736. this->rc_timeout_ = duration;
  737. return (this->derived());
  738. }
  739. /**
  740. * @brief get the default remote call timeout for rpc/rdc
  741. */
  742. inline std::chrono::steady_clock::duration get_default_timeout() const noexcept
  743. {
  744. return this->rc_timeout_;
  745. }
  746. /**
  747. * @brief get the buffer object reference
  748. */
  749. inline buffer_wrap<buffer_type> & buffer() noexcept { return this->buffer_; }
  750. /**
  751. * @brief get the io object reference
  752. */
  753. inline io_t & io() noexcept { return *(this->io_); }
  754. /**
  755. * @brief get the io object reference
  756. */
  757. inline io_t const& io() const noexcept { return *(this->io_); }
  758. protected:
  759. /**
  760. * @brief get the recv/read allocator object reference
  761. */
  762. inline auto & rallocator() noexcept { return this->rallocator_; }
  763. /**
  764. * @brief get the send/write allocator object reference
  765. */
  766. inline auto & wallocator() noexcept { return this->wallocator_; }
  767. inline const char* life_id () noexcept { return this->life_id_.get(); }
  768. inline void reset_life_id () noexcept { this->life_id_ = std::make_unique<char>(); }
  769. protected:
  770. /// The memory to use for handler-based custom memory allocation. used fo recv/read.
  771. handler_memory<std::true_type , assizer<args_t>> rallocator_;
  772. /// The memory to use for handler-based custom memory allocation. used fo send/write.
  773. handler_memory<std::false_type, assizer<args_t>> wallocator_;
  774. /// listener
  775. listener_t listener_;
  776. /// The io_context wrapper used to handle the accept event.
  777. std::shared_ptr<io_t> io_;
  778. /// buffer
  779. buffer_wrap<buffer_type> buffer_;
  780. /// state
  781. std::atomic<state_t> state_ = state_t::stopped;
  782. /// socket, shoule be destroyed before io_context
  783. std::shared_ptr<socket_type> socket_;
  784. /// Remote call (rpc/rdc) response timeout.
  785. std::chrono::steady_clock::duration rc_timeout_ = std::chrono::milliseconds(http_execute_timeout);
  786. /// the pointer of ecs_t
  787. std::shared_ptr<ecs_base> ecs_;
  788. /// Whether the async_read... is called.
  789. bool reading_ = false;
  790. /// @see client life id
  791. std::unique_ptr<char> life_id_ = std::make_unique<char>();
  792. #if defined(_DEBUG) || defined(DEBUG)
  793. bool is_stop_called_ = false;
  794. std::atomic<int> post_send_counter_ = 0;
  795. std::atomic<int> post_recv_counter_ = 0;
  796. #endif
  797. };
  798. }
  799. namespace asio2
  800. {
  801. using serial_port_args = detail::template_args_serial_port;
  802. template<class derived_t, class args_t>
  803. using serial_port_impl_t = detail::serial_port_impl_t<derived_t, args_t>;
  804. template<class derived_t>
  805. class serial_port_t : public detail::serial_port_impl_t<derived_t, detail::template_args_serial_port>
  806. {
  807. public:
  808. using detail::serial_port_impl_t<derived_t, detail::template_args_serial_port>::serial_port_impl_t;
  809. };
  810. /**
  811. * The serial_port class provides a wrapper over serial port functionality.
  812. * You can use the following commands to query the serial device under Linux:
  813. * cat /proc/tty/driver/serial
  814. * If this object is created as a shared_ptr like std::shared_ptr<asio2::serial_port> sp;
  815. * you must call the sp->stop() manual when exit, otherwise maybe cause memory leaks.
  816. */
  817. class serial_port : public serial_port_t<serial_port>
  818. {
  819. public:
  820. using serial_port_t<serial_port>::serial_port_t;
  821. };
  822. }
  823. #include <asio2/base/detail/pop_options.hpp>
  824. #endif // !__ASIO2_SERIAL_PORT_HPP__