Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

720 lignes
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__ */