serial_port_base.ipp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. //
  2. // impl/serial_port_base.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. // Copyright (c) 2008 Rep Invariant Systems, Inc. ([email protected])
  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 BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP
  12. #define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include <boost/asio/detail/config.hpp>
  17. #if defined(BOOST_ASIO_HAS_SERIAL_PORT)
  18. #include <stdexcept>
  19. #include <boost/asio/error.hpp>
  20. #include <boost/asio/serial_port_base.hpp>
  21. #include <boost/asio/detail/throw_exception.hpp>
  22. #if defined(GENERATING_DOCUMENTATION)
  23. # define BOOST_ASIO_OPTION_STORAGE implementation_defined
  24. #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  25. # define BOOST_ASIO_OPTION_STORAGE DCB
  26. #else
  27. # define BOOST_ASIO_OPTION_STORAGE termios
  28. #endif
  29. #include <boost/asio/detail/push_options.hpp>
  30. namespace boost {
  31. namespace asio {
  32. BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store(
  33. BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const
  34. {
  35. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  36. storage.BaudRate = value_;
  37. #else
  38. speed_t baud;
  39. switch (value_)
  40. {
  41. // Do POSIX-specified rates first.
  42. case 0: baud = B0; break;
  43. case 50: baud = B50; break;
  44. case 75: baud = B75; break;
  45. case 110: baud = B110; break;
  46. case 134: baud = B134; break;
  47. case 150: baud = B150; break;
  48. case 200: baud = B200; break;
  49. case 300: baud = B300; break;
  50. case 600: baud = B600; break;
  51. case 1200: baud = B1200; break;
  52. case 1800: baud = B1800; break;
  53. case 2400: baud = B2400; break;
  54. case 4800: baud = B4800; break;
  55. case 9600: baud = B9600; break;
  56. case 19200: baud = B19200; break;
  57. case 38400: baud = B38400; break;
  58. // And now the extended ones conditionally.
  59. # ifdef B7200
  60. case 7200: baud = B7200; break;
  61. # endif
  62. # ifdef B14400
  63. case 14400: baud = B14400; break;
  64. # endif
  65. # ifdef B57600
  66. case 57600: baud = B57600; break;
  67. # endif
  68. # ifdef B115200
  69. case 115200: baud = B115200; break;
  70. # endif
  71. # ifdef B230400
  72. case 230400: baud = B230400; break;
  73. # endif
  74. # ifdef B460800
  75. case 460800: baud = B460800; break;
  76. # endif
  77. # ifdef B500000
  78. case 500000: baud = B500000; break;
  79. # endif
  80. # ifdef B576000
  81. case 576000: baud = B576000; break;
  82. # endif
  83. # ifdef B921600
  84. case 921600: baud = B921600; break;
  85. # endif
  86. # ifdef B1000000
  87. case 1000000: baud = B1000000; break;
  88. # endif
  89. # ifdef B1152000
  90. case 1152000: baud = B1152000; break;
  91. # endif
  92. # ifdef B2000000
  93. case 2000000: baud = B2000000; break;
  94. # endif
  95. # ifdef B3000000
  96. case 3000000: baud = B3000000; break;
  97. # endif
  98. # ifdef B3500000
  99. case 3500000: baud = B3500000; break;
  100. # endif
  101. # ifdef B4000000
  102. case 4000000: baud = B4000000; break;
  103. # endif
  104. default:
  105. ec = boost::asio::error::invalid_argument;
  106. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  107. }
  108. # if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
  109. ::cfsetspeed(&storage, baud);
  110. # else
  111. ::cfsetispeed(&storage, baud);
  112. ::cfsetospeed(&storage, baud);
  113. # endif
  114. #endif
  115. ec = boost::system::error_code();
  116. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  117. }
  118. BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load(
  119. const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec)
  120. {
  121. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  122. value_ = storage.BaudRate;
  123. #else
  124. speed_t baud = ::cfgetospeed(&storage);
  125. switch (baud)
  126. {
  127. // First do those specified by POSIX.
  128. case B0: value_ = 0; break;
  129. case B50: value_ = 50; break;
  130. case B75: value_ = 75; break;
  131. case B110: value_ = 110; break;
  132. case B134: value_ = 134; break;
  133. case B150: value_ = 150; break;
  134. case B200: value_ = 200; break;
  135. case B300: value_ = 300; break;
  136. case B600: value_ = 600; break;
  137. case B1200: value_ = 1200; break;
  138. case B1800: value_ = 1800; break;
  139. case B2400: value_ = 2400; break;
  140. case B4800: value_ = 4800; break;
  141. case B9600: value_ = 9600; break;
  142. case B19200: value_ = 19200; break;
  143. case B38400: value_ = 38400; break;
  144. // Now conditionally handle a bunch of extended rates.
  145. # ifdef B7200
  146. case B7200: value_ = 7200; break;
  147. # endif
  148. # ifdef B14400
  149. case B14400: value_ = 14400; break;
  150. # endif
  151. # ifdef B57600
  152. case B57600: value_ = 57600; break;
  153. # endif
  154. # ifdef B115200
  155. case B115200: value_ = 115200; break;
  156. # endif
  157. # ifdef B230400
  158. case B230400: value_ = 230400; break;
  159. # endif
  160. # ifdef B460800
  161. case B460800: value_ = 460800; break;
  162. # endif
  163. # ifdef B500000
  164. case B500000: value_ = 500000; break;
  165. # endif
  166. # ifdef B576000
  167. case B576000: value_ = 576000; break;
  168. # endif
  169. # ifdef B921600
  170. case B921600: value_ = 921600; break;
  171. # endif
  172. # ifdef B1000000
  173. case B1000000: value_ = 1000000; break;
  174. # endif
  175. # ifdef B1152000
  176. case B1152000: value_ = 1152000; break;
  177. # endif
  178. # ifdef B2000000
  179. case B2000000: value_ = 2000000; break;
  180. # endif
  181. # ifdef B3000000
  182. case B3000000: value_ = 3000000; break;
  183. # endif
  184. # ifdef B3500000
  185. case B3500000: value_ = 3500000; break;
  186. # endif
  187. # ifdef B4000000
  188. case B4000000: value_ = 4000000; break;
  189. # endif
  190. default:
  191. value_ = 0;
  192. ec = boost::asio::error::invalid_argument;
  193. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  194. }
  195. #endif
  196. ec = boost::system::error_code();
  197. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  198. }
  199. serial_port_base::flow_control::flow_control(
  200. serial_port_base::flow_control::type t)
  201. : value_(t)
  202. {
  203. if (t != none && t != software && t != hardware)
  204. {
  205. std::out_of_range ex("invalid flow_control value");
  206. boost::asio::detail::throw_exception(ex);
  207. }
  208. }
  209. BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::store(
  210. BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const
  211. {
  212. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  213. storage.fOutxCtsFlow = FALSE;
  214. storage.fOutxDsrFlow = FALSE;
  215. storage.fTXContinueOnXoff = TRUE;
  216. storage.fDtrControl = DTR_CONTROL_ENABLE;
  217. storage.fDsrSensitivity = FALSE;
  218. storage.fOutX = FALSE;
  219. storage.fInX = FALSE;
  220. storage.fRtsControl = RTS_CONTROL_ENABLE;
  221. switch (value_)
  222. {
  223. case none:
  224. break;
  225. case software:
  226. storage.fOutX = TRUE;
  227. storage.fInX = TRUE;
  228. break;
  229. case hardware:
  230. storage.fOutxCtsFlow = TRUE;
  231. storage.fRtsControl = RTS_CONTROL_HANDSHAKE;
  232. break;
  233. default:
  234. break;
  235. }
  236. #else
  237. switch (value_)
  238. {
  239. case none:
  240. storage.c_iflag &= ~(IXOFF | IXON);
  241. # if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
  242. storage.c_cflag &= ~CRTSCTS;
  243. # elif defined(__QNXNTO__)
  244. storage.c_cflag &= ~(IHFLOW | OHFLOW);
  245. # endif
  246. break;
  247. case software:
  248. storage.c_iflag |= IXOFF | IXON;
  249. # if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
  250. storage.c_cflag &= ~CRTSCTS;
  251. # elif defined(__QNXNTO__)
  252. storage.c_cflag &= ~(IHFLOW | OHFLOW);
  253. # endif
  254. break;
  255. case hardware:
  256. # if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
  257. storage.c_iflag &= ~(IXOFF | IXON);
  258. storage.c_cflag |= CRTSCTS;
  259. break;
  260. # elif defined(__QNXNTO__)
  261. storage.c_iflag &= ~(IXOFF | IXON);
  262. storage.c_cflag |= (IHFLOW | OHFLOW);
  263. break;
  264. # else
  265. ec = boost::asio::error::operation_not_supported;
  266. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  267. # endif
  268. default:
  269. break;
  270. }
  271. #endif
  272. ec = boost::system::error_code();
  273. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  274. }
  275. BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::load(
  276. const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec)
  277. {
  278. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  279. if (storage.fOutX && storage.fInX)
  280. {
  281. value_ = software;
  282. }
  283. else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE)
  284. {
  285. value_ = hardware;
  286. }
  287. else
  288. {
  289. value_ = none;
  290. }
  291. #else
  292. if (storage.c_iflag & (IXOFF | IXON))
  293. {
  294. value_ = software;
  295. }
  296. # if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
  297. else if (storage.c_cflag & CRTSCTS)
  298. {
  299. value_ = hardware;
  300. }
  301. # elif defined(__QNXNTO__)
  302. else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW)
  303. {
  304. value_ = hardware;
  305. }
  306. # endif
  307. else
  308. {
  309. value_ = none;
  310. }
  311. #endif
  312. ec = boost::system::error_code();
  313. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  314. }
  315. serial_port_base::parity::parity(serial_port_base::parity::type t)
  316. : value_(t)
  317. {
  318. if (t != none && t != odd && t != even)
  319. {
  320. std::out_of_range ex("invalid parity value");
  321. boost::asio::detail::throw_exception(ex);
  322. }
  323. }
  324. BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::store(
  325. BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const
  326. {
  327. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  328. switch (value_)
  329. {
  330. case none:
  331. storage.fParity = FALSE;
  332. storage.Parity = NOPARITY;
  333. break;
  334. case odd:
  335. storage.fParity = TRUE;
  336. storage.Parity = ODDPARITY;
  337. break;
  338. case even:
  339. storage.fParity = TRUE;
  340. storage.Parity = EVENPARITY;
  341. break;
  342. default:
  343. break;
  344. }
  345. #else
  346. switch (value_)
  347. {
  348. case none:
  349. storage.c_iflag |= IGNPAR;
  350. storage.c_cflag &= ~(PARENB | PARODD);
  351. break;
  352. case even:
  353. storage.c_iflag &= ~(IGNPAR | PARMRK);
  354. storage.c_iflag |= INPCK;
  355. storage.c_cflag |= PARENB;
  356. storage.c_cflag &= ~PARODD;
  357. break;
  358. case odd:
  359. storage.c_iflag &= ~(IGNPAR | PARMRK);
  360. storage.c_iflag |= INPCK;
  361. storage.c_cflag |= (PARENB | PARODD);
  362. break;
  363. default:
  364. break;
  365. }
  366. #endif
  367. ec = boost::system::error_code();
  368. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  369. }
  370. BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::load(
  371. const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec)
  372. {
  373. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  374. if (storage.Parity == EVENPARITY)
  375. {
  376. value_ = even;
  377. }
  378. else if (storage.Parity == ODDPARITY)
  379. {
  380. value_ = odd;
  381. }
  382. else
  383. {
  384. value_ = none;
  385. }
  386. #else
  387. if (storage.c_cflag & PARENB)
  388. {
  389. if (storage.c_cflag & PARODD)
  390. {
  391. value_ = odd;
  392. }
  393. else
  394. {
  395. value_ = even;
  396. }
  397. }
  398. else
  399. {
  400. value_ = none;
  401. }
  402. #endif
  403. ec = boost::system::error_code();
  404. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  405. }
  406. serial_port_base::stop_bits::stop_bits(
  407. serial_port_base::stop_bits::type t)
  408. : value_(t)
  409. {
  410. if (t != one && t != onepointfive && t != two)
  411. {
  412. std::out_of_range ex("invalid stop_bits value");
  413. boost::asio::detail::throw_exception(ex);
  414. }
  415. }
  416. BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store(
  417. BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const
  418. {
  419. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  420. switch (value_)
  421. {
  422. case one:
  423. storage.StopBits = ONESTOPBIT;
  424. break;
  425. case onepointfive:
  426. storage.StopBits = ONE5STOPBITS;
  427. break;
  428. case two:
  429. storage.StopBits = TWOSTOPBITS;
  430. break;
  431. default:
  432. break;
  433. }
  434. #else
  435. switch (value_)
  436. {
  437. case one:
  438. storage.c_cflag &= ~CSTOPB;
  439. break;
  440. case two:
  441. storage.c_cflag |= CSTOPB;
  442. break;
  443. default:
  444. ec = boost::asio::error::operation_not_supported;
  445. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  446. }
  447. #endif
  448. ec = boost::system::error_code();
  449. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  450. }
  451. BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load(
  452. const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec)
  453. {
  454. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  455. if (storage.StopBits == ONESTOPBIT)
  456. {
  457. value_ = one;
  458. }
  459. else if (storage.StopBits == ONE5STOPBITS)
  460. {
  461. value_ = onepointfive;
  462. }
  463. else if (storage.StopBits == TWOSTOPBITS)
  464. {
  465. value_ = two;
  466. }
  467. else
  468. {
  469. value_ = one;
  470. }
  471. #else
  472. value_ = (storage.c_cflag & CSTOPB) ? two : one;
  473. #endif
  474. ec = boost::system::error_code();
  475. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  476. }
  477. serial_port_base::character_size::character_size(unsigned int t)
  478. : value_(t)
  479. {
  480. if (t < 5 || t > 8)
  481. {
  482. std::out_of_range ex("invalid character_size value");
  483. boost::asio::detail::throw_exception(ex);
  484. }
  485. }
  486. BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::store(
  487. BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const
  488. {
  489. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  490. storage.ByteSize = value_;
  491. #else
  492. storage.c_cflag &= ~CSIZE;
  493. switch (value_)
  494. {
  495. case 5: storage.c_cflag |= CS5; break;
  496. case 6: storage.c_cflag |= CS6; break;
  497. case 7: storage.c_cflag |= CS7; break;
  498. case 8: storage.c_cflag |= CS8; break;
  499. default: break;
  500. }
  501. #endif
  502. ec = boost::system::error_code();
  503. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  504. }
  505. BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::load(
  506. const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec)
  507. {
  508. #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
  509. value_ = storage.ByteSize;
  510. #else
  511. if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; }
  512. else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; }
  513. else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; }
  514. else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; }
  515. else
  516. {
  517. // Hmmm, use 8 for now.
  518. value_ = 8;
  519. }
  520. #endif
  521. ec = boost::system::error_code();
  522. BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
  523. }
  524. } // namespace asio
  525. } // namespace boost
  526. #include <boost/asio/detail/pop_options.hpp>
  527. #undef BOOST_ASIO_OPTION_STORAGE
  528. #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
  529. #endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP