Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

720 lines
26 KiB

  1. /*!
  2. * \file /utl/com/_1wire.h
  3. * \brief An 1-wire interface implementation
  4. *
  5. * Copyright (C) 2018 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #ifndef __utl_com_1wire_h__
  22. #define __utl_com_1wire_h__
  23. #include <utl/impl/impl.h>
  24. #include <utl/helper/crtp.h>
  25. #include <utl/meta/sfinae.h>
  26. #include <utl/com/_1wire_id.h>
  27. namespace utl {
  28. /*!
  29. * \ingroup Communication
  30. * \brief Abstract base class interface for 1-wire bus
  31. */
  32. //!@{
  33. /*!
  34. * \name Friend API to provide common functionality to all specializations
  35. */
  36. namespace _1wire_i_det {
  37. template <typename _T> byte_t _touch (_T& obj, byte_t out, typename _T::Speed s);
  38. template <typename _T> void _match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
  39. template <typename _T> void _match_n_ovdr (_T& obj, _1wire_id_t& id);
  40. template <typename _T> void _skip (_T& obj, typename _T::Speed s);
  41. template <typename _T> void _skip_n_ovdr (_T& obj);
  42. template <typename _T> _1wire_id_t _first (_T& obj, typename _T::Speed s, bool alarm);
  43. template <typename _T> _1wire_id_t _next (_T& obj, typename _T::Speed s, bool alarm);
  44. }
  45. /*!
  46. * \brief
  47. * Template base class for 1-wire communication interface using CRTP
  48. * \param impl_t The CRTP type (the derived/implementation class typename).
  49. */
  50. template <typename impl_t>
  51. class _1wire_i {
  52. _CRTP_IMPL(impl_t);
  53. public:
  54. using type = _1wire_i; //!< Export type as identity meta-function
  55. //! 1-wire bus speed
  56. enum class Speed { STD =0, OVDR };
  57. /*!
  58. * \name Object lifetime
  59. */
  60. //!@{
  61. protected:
  62. _1wire_i () = default; //!< Allow constructor from derived only
  63. ~_1wire_i () = default; //!< Allow destructor from derived only
  64. _1wire_i (const _1wire_i&) = delete; //!< No copies
  65. _1wire_i& operator= (const _1wire_i&) = delete;
  66. //!@}
  67. /*!
  68. * \name Implementation requirements
  69. * \note
  70. * In order for the implementation to have the following as private members too
  71. * it need to declare this class as friend
  72. */
  73. //!@{
  74. private:
  75. Speed speed () const { return impl().speed(); } //!< Get the 1-wire bus speed
  76. void speed (Speed s) { return impl().speed(s); } //!< Set the 1-wire bus speed
  77. //! Write a bit to the 1-Wire bus, return response/write status and provide the recovery time.
  78. bool bit (bool b) { return impl().bit(b); }
  79. bool _reset (Speed s){ return impl()._reset(s); } //!< Generate a 1-wire reset and return the operation status
  80. //!@}
  81. /*!
  82. * \name Friends api to provide functionality to all class specializations
  83. */
  84. //!@{
  85. private:
  86. enum Command {
  87. CMD_READ_ROM = 0x33,
  88. CMD_OVDR_SKIP = 0x3C,
  89. CMD_MATCH = 0x55,
  90. CMD_OVDR_MATCH = 0x69,
  91. CMD_SKIP = 0xCC,
  92. CMD_ALARM_SEARCH = 0xEC,
  93. CMD_SEARCH_ROM = 0xF0
  94. };
  95. template <typename _T> friend byte_t _1wire_i_det::_touch (_T&, byte_t, typename _T::Speed);
  96. template <typename _T> friend void _1wire_i_det::_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
  97. template <typename _T> friend void _1wire_i_det::_match_n_ovdr (_T& obj, _1wire_id_t& id);
  98. template <typename _T> friend void _1wire_i_det::_skip (_T& obj, typename _T::Speed s);
  99. template <typename _T> friend void _1wire_i_det::_skip_n_ovdr (_T& obj);
  100. template <typename _T> friend _1wire_id_t _1wire_i_det::_first (_T&, typename _T::Speed, bool);
  101. template <typename _T> friend _1wire_id_t _1wire_i_det::_next (_T&, typename _T::Speed, bool);
  102. //!@}
  103. /*!
  104. * \name User functionality provided by the interface
  105. */
  106. //!@{
  107. public:
  108. /*!
  109. * \brief
  110. * Generate a 1-wire reset
  111. * \param s Bus speed
  112. * \return The status of the operation
  113. * \arg 0 Fail
  114. * \arg 1 Success
  115. */
  116. bool reset (Speed s = Speed::STD) {
  117. return _reset (s);
  118. }
  119. /*!
  120. * Transmit a byte to 1-Wire bus and read the response
  121. * \param out The byte to write
  122. * \param s Bus speed to use
  123. * \return The byte received.
  124. */
  125. byte_t tx_data (byte_t out, Speed s = Speed::STD) {
  126. return _1wire_i_det::_touch (*this, out, s);
  127. }
  128. /*!
  129. * Transmit a number of bytes to 1-wire bus and read the response
  130. * \param out Pointer to data to transmit
  131. * \param in Pointer to data to store
  132. * \param n Number of bytes
  133. * \param s Speed to use
  134. * \return The number of transmitted bytes
  135. */
  136. size_t tx_data (const byte_t *out, byte_t *in, size_t n, Speed s = Speed::STD);
  137. /*!
  138. * Receive a byte from 1-Wire bus while transmitting 0xFF
  139. * \param s Bus speed to use
  140. * \return The byte received.
  141. */
  142. byte_t rx_data (Speed s = Speed::STD) {
  143. return _1wire_i_det::_touch (*this, 0xFF, s);
  144. }
  145. /*!
  146. * Receive a number of bytes from 1-wire bus while transmitting 0xFFs
  147. * \param in Pointer to data to store
  148. * \param n Number of bytes
  149. * \param s Speed to use
  150. * \return The number of transmitted bytes
  151. */
  152. size_t rx_data (byte_t *in, size_t n, Speed s = Speed::STD);
  153. /*!
  154. * Send match rom command
  155. * \param id The ID to select on the bus
  156. * \param s The speed to use for the command
  157. */
  158. void match (_1wire_id_t& id, Speed s = Speed::STD) {
  159. _1wire_i_det::_match (*this, id, s);
  160. }
  161. /*!
  162. * Match and overdrive sequence
  163. * \param obj The object from which we call private members
  164. * \param id The ID to select on the bus
  165. */
  166. void match_n_ovdr (_1wire_id_t& id) {
  167. _1wire_i_det::_match_n_ovdr (*this, id);
  168. }
  169. /*!
  170. * Send skip command to the bus
  171. * \param id The ID to select on the bus
  172. */
  173. void skip (Speed s = Speed::STD) {
  174. _1wire_i_det::_skip (*this, s);
  175. }
  176. /*!
  177. * Send the Skip and Overdrive sequence
  178. */
  179. void skip_n_ovdr () {
  180. _1wire_i_det::_skip_n_ovdr (*this);
  181. }
  182. /*!
  183. * \brief
  184. * 'first' operation, to search on the 1-Wire for the first device.
  185. * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
  186. * \param s The bus speed
  187. * \param alarm If set, search for alarm devices
  188. * \return ID The romID
  189. * \arg nullDev Indicate no [more] device[s]
  190. */
  191. _1wire_id_t first (Speed s = Speed::STD, bool alarm =false) {
  192. return _1wire_i_det::_first (*this, s, alarm);
  193. }
  194. /*!
  195. * \brief
  196. * 'next' operation, to search on the 1-Wire for the next device.
  197. * This search is usually performed after a 'first' operation or another 'next' operation.
  198. * Based on maxim-ic application note 187.
  199. * \param s The bus speed
  200. * \param alarm If set, search for alarm devices
  201. * \return ID The romID
  202. * \arg nullDev Indicate no [more] device[s]
  203. */
  204. _1wire_id_t next (Speed s = Speed::STD, bool alarm =false) {
  205. return _1wire_i_det::_next (*this, s, alarm);
  206. }
  207. //!@}
  208. private:
  209. _1wire_id_t dec_ {_1wire_id_t::nullDev()}; /*!<
  210. * Hold the algorithm's select bit when a discrepancy
  211. * is detected. We use this variable to navigate to the
  212. * ROM tree as we store the path we take each time (0-1).
  213. * Each bit represent a bit position in the ROM ID.
  214. */
  215. _1wire_id_t pos_ {_1wire_id_t::nullDev()}; /*!<
  216. * Hold the discrepancy position. We use this variable to
  217. * navigate to the ROM tree as we store the crossroads(1) we encounter.
  218. * Each bit represent a bit position in the ROM ID.
  219. */
  220. _1wire_id_t cur_ {_1wire_id_t::nullDev()}; //! Current rom discrepancy state
  221. };
  222. template <typename _I>
  223. size_t _1wire_i<_I>::tx_data (const byte_t *out, byte_t *in, size_t n, Speed s){
  224. for (size_t nn {n} ; nn ; --nn)
  225. *in++ = tx_data (*out++, s);
  226. return n;
  227. }
  228. template <typename _I>
  229. size_t _1wire_i<_I>::rx_data(byte_t *in, size_t n, Speed s) {
  230. for (size_t nn {n} ; nn ; --nn)
  231. *in++ = tx_data (0xFF, s);
  232. return n;
  233. }
  234. /*!
  235. * \brief
  236. * A virtual base class implementation
  237. * \param impl_t = virtual_tag
  238. */
  239. template <>
  240. class _1wire_i <virtual_tag> {
  241. public:
  242. using type = _1wire_i<virtual_tag>; //!< Export type as identity meta-function
  243. //! 1-wire bus speed
  244. enum class Speed { STD =0, OVDR };
  245. /*!
  246. * \name Object lifetime
  247. */
  248. //!@{
  249. protected:
  250. _1wire_i () = default; //!< Allow constructor from derived only
  251. _1wire_i (const type&) = delete; //!< No copies
  252. type& operator= (const type&) = delete;
  253. public:
  254. virtual ~_1wire_i () = default; //!< Virtual default destructor
  255. //!@}
  256. /*!
  257. * \name Implementation requirements
  258. */
  259. //!@{
  260. private:
  261. virtual Speed speed () const =0; //!< Get the 1-wire bus speed
  262. virtual void speed (Speed) =0; //!< Set the 1-wire bus speed
  263. virtual bool bit () =0; //!< Read a bit from the 1-Wire bus, return it and provide the recovery time.
  264. virtual bool bit (bool) =0; //!< Write a bit to the 1-Wire bus, return write status and provide the recovery time.
  265. virtual bool _reset (Speed) =0; //!< Generate a 1-wire reset and return the operation status
  266. //!@}
  267. /*!
  268. * \name Friends api to provide functionality to all class specializations
  269. */
  270. //!@{
  271. private:
  272. enum Command {
  273. CMD_READ_ROM = 0x33,
  274. CMD_OVDR_SKIP = 0x3C,
  275. CMD_MATCH = 0x55,
  276. CMD_OVDR_MATCH = 0x69,
  277. CMD_SKIP = 0xCC,
  278. CMD_ALARM_SEARCH = 0xEC,
  279. CMD_SEARCH_ROM = 0xF0
  280. };
  281. template <typename _T> friend byte_t _1wire_i_det::_touch (_T&, byte_t, typename _T::Speed);
  282. template <typename _T> friend void _1wire_i_det::_match (_T& obj, _1wire_id_t& id, typename _T::Speed s);
  283. template <typename _T> friend void _1wire_i_det::_match_n_ovdr (_T& obj, _1wire_id_t& id);
  284. template <typename _T> friend void _1wire_i_det::_skip (_T& obj, typename _T::Speed s);
  285. template <typename _T> friend void _1wire_i_det::_skip_n_ovdr (_T& obj);
  286. template <typename _T> friend _1wire_id_t _1wire_i_det::_first (_T&, typename _T::Speed, bool);
  287. template <typename _T> friend _1wire_id_t _1wire_i_det::_next (_T&, typename _T::Speed, bool);
  288. //!@}
  289. /*!
  290. * \name User functionality provided by the interface
  291. */
  292. //!@{
  293. public:
  294. /*!
  295. * \brief
  296. * Generate a 1-wire reset
  297. * \param s Bus speed
  298. * \return The status of the operation
  299. * \arg 0 Fail
  300. * \arg 1 Success
  301. */
  302. bool reset (Speed s = Speed::STD) {
  303. return _reset (s);
  304. }
  305. /*!
  306. * Transmit a byte to 1-Wire bus and read the response
  307. * \param out The byte to write
  308. * \param s Bus speed to use
  309. * \return The byte received.
  310. */
  311. byte_t tx_data (byte_t out, Speed s = Speed::STD) {
  312. return _1wire_i_det::_touch (*this, out, s);
  313. }
  314. /*!
  315. * Transmit a number of bytes to 1-wire bus and read the response
  316. * \param out Pointer to data to transmit
  317. * \param in Pointer to data to store
  318. * \param n Number of bytes
  319. * \param s Speed to use
  320. * \return The number of transmitted bytes
  321. */
  322. size_t tx_data (const byte_t *out, byte_t *in, size_t n, Speed s = Speed::STD);
  323. /*!
  324. * Receive a byte from 1-Wire bus while transmitting 0xFF
  325. * \param s Bus speed to use
  326. * \return The byte received.
  327. */
  328. byte_t rx_data (Speed s = Speed::STD) {
  329. return _1wire_i_det::_touch (*this, 0xFF, s);
  330. }
  331. /*!
  332. * Receive a number of bytes from 1-wire bus while transmitting 0xFFs
  333. * \param in Pointer to data to store
  334. * \param n Number of bytes
  335. * \param s Speed to use
  336. * \return The number of transmitted bytes
  337. */
  338. size_t rx_data (byte_t *in, size_t n, Speed s = Speed::STD);
  339. /*!
  340. * Send match rom command
  341. * \param id The ID to select on the bus
  342. * \param s The speed to use for the command
  343. */
  344. void match (_1wire_id_t& id, Speed s = Speed::STD) {
  345. _1wire_i_det::_match (*this, id, s);
  346. }
  347. /*!
  348. * Match and overdrive sequence
  349. * \param obj The object from which we call private members
  350. * \param id The ID to select on the bus
  351. */
  352. void match_n_ovdr (_1wire_id_t& id) {
  353. _1wire_i_det::_match_n_ovdr (*this, id);
  354. }
  355. /*!
  356. * Send skip command to the bus
  357. * \param id The ID to select on the bus
  358. */
  359. void skip (Speed s = Speed::STD) {
  360. _1wire_i_det::_skip (*this, s);
  361. }
  362. /*!
  363. * Send the Skip and Overdrive sequence
  364. */
  365. void skip_n_ovdr () {
  366. _1wire_i_det::_skip_n_ovdr (*this);
  367. }
  368. /*!
  369. * \brief
  370. * 'first' operation, to search on the 1-Wire for the first device.
  371. * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
  372. * \param s The bus speed
  373. * \param alarm If set, search for alarm devices
  374. * \return ID The romID
  375. * \arg nullDev Indicate no [more] device[s]
  376. */
  377. _1wire_id_t first (Speed s = Speed::STD, bool alarm =false) {
  378. return _1wire_i_det::_first (*this, s, alarm);
  379. }
  380. /*!
  381. * \brief
  382. * 'next' operation, to search on the 1-Wire for the next device.
  383. * This search is usually performed after a 'first' operation or another 'next' operation.
  384. * Based on maxim-ic application note 187.
  385. * \param s The bus speed
  386. * \param alarm If set, search for alarm devices
  387. * \return ID The romID
  388. * \arg nullDev Indicate no [more] device[s]
  389. */
  390. _1wire_id_t next (Speed s = Speed::STD, bool alarm =false) {
  391. return _1wire_i_det::_next (*this, s, alarm);
  392. }
  393. //!@}
  394. private:
  395. _1wire_id_t dec_ {_1wire_id_t::nullDev()}; /*!<
  396. * Hold the algorithm's select bit when a discrepancy
  397. * is detected. We use this variable to navigate to the
  398. * ROM tree as we store the path we take each time (0-1).
  399. * Each bit represent a bit position in the ROM ID.
  400. */
  401. _1wire_id_t pos_ {_1wire_id_t::nullDev()}; /*!<
  402. * Hold the discrepancy position. We use this variable to
  403. * navigate to the ROM tree as we store the crossroads(1) we encounter.
  404. * Each bit represent a bit position in the ROM ID.
  405. */
  406. _1wire_id_t cur_ {_1wire_id_t::nullDev()}; //! Current rom discrepancy state
  407. };
  408. size_t _1wire_i<virtual_tag>::tx_data (const byte_t *out, byte_t *in, size_t n, Speed s){
  409. for (size_t nn {n} ; nn ; --nn)
  410. *in++ = tx_data (*out++, s);
  411. return n;
  412. }
  413. size_t _1wire_i<virtual_tag>::rx_data(byte_t *in, size_t n, Speed s) {
  414. for (size_t nn {n} ; nn ; --nn)
  415. *in++ = tx_data (0xFF, s);
  416. return n;
  417. }
  418. /*!
  419. * \name Friend API to provide common functionality to all specializations
  420. */
  421. //!@{
  422. namespace _1wire_i_det {
  423. /*!
  424. * \brief
  425. * Write a byte to 1-Wire bus and read the response
  426. * \param obj The object from which we call private members
  427. * \param b The byte to write
  428. * \param s Bus speed to use
  429. * \return The byte received.
  430. */
  431. template <typename _T>
  432. byte_t _touch (_T& obj, byte_t out, typename _T::Speed s) {
  433. byte_t ret {0};
  434. // Select speed once
  435. if (obj.speed () != s)
  436. obj.speed (s);
  437. for (uint8_t i =8; i>0 ; --i) {
  438. ret >>= 1;
  439. ret |= (obj.bit (out & 0x01)) ? 0x80 : 0x00;
  440. out >>= 1;
  441. /*^
  442. * We shift bits to right as LSB comes first and mask it to MSB
  443. * If we need to read we have to write 1
  444. */
  445. }
  446. return ret;
  447. }
  448. /*!
  449. * Send match rom command
  450. * \param obj The object from which we call private members
  451. * \param id The ID to select on the bus
  452. * \param s The speed to use for the command
  453. */
  454. template <typename _T>
  455. void _match (_T& obj, _1wire_id_t& id, typename _T::Speed s) {
  456. _touch (obj, (s == _T::Speed::STD) ? _T::CMD_MATCH : _T::CMD_OVDR_MATCH, s);
  457. for (uint8_t& b : id)
  458. _touch (obj, b, s);
  459. }
  460. /*!
  461. * Match and overdrive sequence
  462. * \param obj The object from which we call private members
  463. * \param id The ID to select on the bus
  464. */
  465. template <typename _T>
  466. void _match_n_ovdr (_T& obj, _1wire_id_t& id) {
  467. _touch (obj, _T::CMD_MATCH, _T::Speed::STD);
  468. for (uint8_t& b : id)
  469. _touch (obj, b, _T::Speed::OVDR);
  470. }
  471. /*!
  472. * Send skip command to the bus
  473. * \param obj The object from which we call private members
  474. * \param id The ID to select on the bus
  475. */
  476. template <typename _T>
  477. void _skip (_T& obj, typename _T::Speed s) {
  478. _touch (obj, (s == _T::Speed::STD) ? _T::CMD_SKIP : _T::CMD_SKIP, s);
  479. }
  480. /*!
  481. * Send the Skip and Overdrive sequence
  482. * \param obj The object from which we call private members
  483. */
  484. template <typename _T>
  485. void _skip_n_ovdr (_T& obj) {
  486. _touch (obj, _T::CMD_OVDR_SKIP, _T::Speed::STD);
  487. }
  488. /*!
  489. * \brief
  490. * 'first' operation, to search on the 1-Wire for the first device.
  491. * This is performed by setting dec_, pos_ and cur_ to zero and then doing the search.
  492. * \param obj The object from which we call private members
  493. * \param s The bus speed
  494. * \return ID The romID
  495. * \arg nullDev Indicate no [more] device[s]
  496. */
  497. template <typename _T>
  498. _1wire_id_t _first (_T& obj, typename _T::Speed s, bool alarm) {
  499. obj.dec_ = obj.pos_ = obj.cur_ = _1wire_id_t::nullDev();
  500. return _next (obj, s, alarm);
  501. }
  502. /*!
  503. * \brief
  504. * 'next' operation, to search on the 1-Wire for the next device.
  505. * This search is usually performed after a 'first' operation or another 'next' operation.
  506. * Based on maxim-ic application note 187.
  507. * \param obj The object from which we call private members
  508. * \param s The bus speed
  509. * \return The romID
  510. * \arg nullDev Indicate no [more] device[s]
  511. */
  512. template <typename _T>
  513. _1wire_id_t _next (_T& obj, typename _T::Speed s, bool alarm) {
  514. uint8_t b, bxx; // bit helper vars
  515. uint8_t i;
  516. _1wire_id_t ID;
  517. do {
  518. if ((obj.pos_ != _1wire_id_t::nullDev()) && (obj.dec_ >= obj.pos_)) {
  519. // dec_ == pos_: We have found all the leafs, already
  520. // dec_ > pos_ : Error
  521. ID = _1wire_id_t::nullDev();
  522. break;
  523. }
  524. if (!obj.reset (s)) {
  525. ID = _1wire_id_t::nullDev();
  526. break;
  527. }
  528. // Issue search command
  529. if (alarm) obj.tx_data (_T::CMD_ALARM_SEARCH, s);
  530. else obj.tx_data (_T::CMD_SEARCH_ROM, s);
  531. // Select speed once
  532. if (obj.speed () != s)
  533. obj.speed (s);
  534. // traverse entire RomID from LSB to MSB
  535. for (i =0 ; i<64 ; ++i) {
  536. // Get response pair bits
  537. bxx = obj.bit (1); // bit
  538. bxx <<= 1;
  539. bxx |= obj.bit (1); // complementary bit
  540. if (bxx == 0x00) {
  541. // 00 - We have discrepancy
  542. obj.cur_.bit (i, 1);
  543. switch (_1wire_id_t::compare (obj.pos_, obj.cur_)) {
  544. default:
  545. case -1:
  546. // pos_ < cur_: This discrepancy is the most far for now. Mark position and select 0.
  547. b = 0;
  548. //dec_.bit (i, (b = 0)); //<-- Its already 0
  549. obj.pos_.bit (i, 1);
  550. break;
  551. case 0:
  552. // pos_ == cur_: This was the last discrepancy in the last pass.
  553. // Select the other branch this time (1)
  554. obj.dec_.bit (i, (b = 1));
  555. break;
  556. case 1:
  557. // pos_ > cur_: We had a discrepancy in a MSB than that, in a previous pass.
  558. // Continue with the last pass decision.
  559. b = obj.dec_.bit (i);
  560. break;
  561. }
  562. // Send selection and update romid
  563. obj.bit (b);
  564. ID.bit (i, b);
  565. }
  566. else if (bxx == 0x01) {
  567. // 01 - All bits of all ROMs are 0s
  568. obj.bit (0);
  569. ID.bit (i, 0);
  570. }
  571. else if (bxx == 0x02) {
  572. // 10 - All bits of all ROMs are 1s
  573. obj.bit (1);
  574. ID.bit (i, 1);
  575. }
  576. else {
  577. // 11 - No device on the bus
  578. ID = _1wire_id_t::nullDev();
  579. break;
  580. }
  581. } // for
  582. if (i == 64 && obj.pos_ == _1wire_id_t::nullDev()) {
  583. // Mark done with only one device
  584. obj.pos_.bit (0, 1);
  585. obj.dec_.bit (0, 1);
  586. }
  587. } while (0);
  588. return ID;
  589. }
  590. } // namespace _1wire_i_det
  591. //!@}
  592. #if defined _utl_have_concepts
  593. /*!
  594. * \name 1-wire type interface concept
  595. */
  596. template <typename T>
  597. concept bool _1wire_c = requires (T t, typename T::Speed s, _1wire_id_t id) {
  598. // Object type
  599. requires not_<std::is_copy_constructible<T>::value>::value;
  600. requires not_<std::is_copy_assignable<T>::value>::value;
  601. // Members
  602. // typename T::Speed;
  603. // typename T::Command;
  604. // Methods
  605. {t.reset(s)} -> bool;
  606. {t.tx_data(1)} -> byte_t;
  607. {t.rx_data(s)} -> byte_t;
  608. t.match(id, s);
  609. t.match_n_ovdr(id);
  610. t.skip(s);
  611. t.skip_n_ovdr();
  612. {t.first(s)} -> _1wire_id_t;
  613. {t.next(s)} -> _1wire_id_t;
  614. };
  615. #else
  616. namespace _1wire_i_det {
  617. using std::declval;
  618. template <class _Tp> using try_reset_t = decltype (declval<_Tp>().reset (declval<typename _Tp::Speed>()));
  619. template <class _Tp> using try_rx1_t = decltype (declval<_Tp>().rx_data (declval<typename _Tp::Speed>()));
  620. template <class _Tp> using try_tx1_t = decltype (declval<_Tp>().tx_data (declval<byte_t>(), declval<typename _Tp::Speed>()));
  621. template <class _Tp> using try_match_t = decltype (declval<_Tp>().match (declval<_1wire_id_t&>(), declval<typename _Tp::Speed>()));
  622. template <class _Tp> using try_match_n_ovdr_t = decltype (declval<_Tp>().match_n_ovdr (declval<_1wire_id_t&>()));
  623. template <class _Tp> using try_skip_t = decltype (declval<_Tp>().skip (declval<typename _Tp::Speed>()));
  624. template <class _Tp> using try_skip_n_ovdr_t = decltype (declval<_Tp>().skip_n_ovdr ());
  625. template <class _Tp> using try_first_t = decltype (declval<_Tp>().first (declval<typename _Tp::Speed>()));
  626. template <class _Tp> using try_next_t = decltype (declval<_Tp>().next (declval<typename _Tp::Speed>()));
  627. //! Primary template to catch any non 1-wire interface types
  628. template <typename _Tp, typename =void>
  629. struct is_1wire_ : false_ {};
  630. //! template to catch a proper 1-wire interface type
  631. template <typename _Tp>
  632. struct is_1wire_ <_Tp,
  633. void_t <
  634. // typename _Tp::Speed,
  635. // typename _Tp::Command,
  636. use_if_same_t <try_reset_t <_Tp>, bool>,
  637. use_if_same_t <try_rx1_t <_Tp>, byte_t>,
  638. //use_if_same_t <try_rx2_t <_Tp>, size_t>,
  639. use_if_same_t <try_tx1_t <_Tp>, byte_t>,
  640. //use_if_same_t <try_tx2_t <_Tp>, size_t>,
  641. use_if_same_t <try_match_t<_Tp>, void>,
  642. use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
  643. use_if_same_t <try_skip_t<_Tp>, void>,
  644. use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
  645. use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
  646. use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
  647. > //!^ SFINAE may apply
  648. > : true_ {};
  649. } // namespace _1wire_i_det
  650. /*!
  651. * Value meta-programming function for 1-wire interface checking
  652. * \param _Tp Type to check
  653. * \return True if _Tp is a 1-wire interface
  654. */
  655. template <typename _Tp>
  656. constexpr bool _1wire_c = _1wire_i_det::is_1wire_<_Tp>::value;
  657. #endif
  658. //!@}
  659. } //namespace utl
  660. #endif /* __utl_com_1wire_h__ */