serial_port_base.ipp 12 KB

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