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.
 
 
 
 

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